From 15aa369268ec9dd9620b761be5eda4a77e635dc3 Mon Sep 17 00:00:00 2001 From: Pileks Date: Fri, 2 Jan 2026 17:35:38 +0100 Subject: [PATCH 1/4] add burn performance package instruction --- .../src/error.rs | 2 + .../instructions/burn_performance_package.rs | 102 +++++++++++ .../src/instructions/mod.rs | 2 + .../src/lib.rs | 5 + scripts/v0.6/burnPerformancePackage.ts | 87 ++++++++++ scripts/v0.7/burnPerformancePackage.ts | 87 ++++++++++ .../types/price_based_performance_package.ts | 102 +++++++++++ .../types/price_based_performance_package.ts | 102 +++++++++++ .../priceBasedPerformancePackage/main.test.ts | 2 + .../unit/burnPerformancePackage.test.ts | 162 ++++++++++++++++++ 10 files changed, 653 insertions(+) create mode 100644 programs/price_based_performance_package/src/instructions/burn_performance_package.rs create mode 100644 scripts/v0.6/burnPerformancePackage.ts create mode 100644 scripts/v0.7/burnPerformancePackage.ts create mode 100644 tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts diff --git a/programs/price_based_performance_package/src/error.rs b/programs/price_based_performance_package/src/error.rs index c7fb1152..102cf187 100644 --- a/programs/price_based_performance_package/src/error.rs +++ b/programs/price_based_performance_package/src/error.rs @@ -28,4 +28,6 @@ pub enum PriceBasedPerformancePackageError { TrancheTokenAmountZero, #[msg("TWAP length must be greater than or equal to 1 day and less than 1 year")] InvalidTwapLength, + #[msg("Invalid admin")] + InvalidAdmin, } diff --git a/programs/price_based_performance_package/src/instructions/burn_performance_package.rs b/programs/price_based_performance_package/src/instructions/burn_performance_package.rs new file mode 100644 index 00000000..038f6adc --- /dev/null +++ b/programs/price_based_performance_package/src/instructions/burn_performance_package.rs @@ -0,0 +1,102 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{self, Burn, Mint, Token, TokenAccount}; + +use super::*; + +pub mod admin { + use anchor_lang::prelude::declare_id; + + // MetaDAO multisig + declare_id!("6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf"); +} + +#[derive(Accounts)] +#[event_cpi] +pub struct BurnPerformancePackage<'info> { + #[account( + mut, + close = spill_account, + has_one = token_mint, + has_one = performance_package_token_vault + )] + pub performance_package: Box>, + + #[account( + mut, + associated_token::mint = token_mint, + associated_token::authority = performance_package + )] + pub performance_package_token_vault: Box>, + + #[account(mut)] + pub admin: Signer<'info>, + + /// CHECK: SOL from account closures go to this account + #[account(mut)] + pub spill_account: UncheckedAccount<'info>, + + #[account(mut, address = performance_package.token_mint)] + pub token_mint: Account<'info, Mint>, + + pub token_program: Program<'info, Token>, +} + +impl BurnPerformancePackage<'_> { + pub fn validate(&self) -> Result<()> { + #[cfg(feature = "production")] + require_keys_eq!( + self.admin.key(), + admin::ID, + PriceBasedPerformancePackageError::InvalidAdmin + ); + + Ok(()) + } + + pub fn handle(ctx: Context) -> Result<()> { + let performance_package = &ctx.accounts.performance_package; + + let seeds = &[ + b"performance_package", + performance_package.create_key.as_ref(), + &[performance_package.pda_bump], + ]; + let signer = &[&seeds[..]]; + + // Burn any remaining tokens in the performance package token vault + if ctx.accounts.performance_package_token_vault.amount > 0 { + token::burn( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + Burn { + mint: ctx.accounts.token_mint.to_account_info(), + from: ctx + .accounts + .performance_package_token_vault + .to_account_info(), + authority: performance_package.to_account_info(), + }, + signer, + ), + ctx.accounts.performance_package_token_vault.amount, + )?; + } + + token::close_account(CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + token::CloseAccount { + account: ctx + .accounts + .performance_package_token_vault + .to_account_info(), + destination: ctx.accounts.spill_account.to_account_info(), + authority: ctx.accounts.performance_package.to_account_info(), + }, + signer, + ))?; + + // Performance package account gets closed using close constraint + + Ok(()) + } +} diff --git a/programs/price_based_performance_package/src/instructions/mod.rs b/programs/price_based_performance_package/src/instructions/mod.rs index b3262291..b85ac90e 100644 --- a/programs/price_based_performance_package/src/instructions/mod.rs +++ b/programs/price_based_performance_package/src/instructions/mod.rs @@ -1,5 +1,6 @@ use super::*; +pub mod burn_performance_package; pub mod change_performance_package_authority; pub mod complete_unlock; pub mod execute_change; @@ -7,6 +8,7 @@ pub mod initialize_performance_package; pub mod propose_change; pub mod start_unlock; +pub use burn_performance_package::*; pub use change_performance_package_authority::*; pub use complete_unlock::*; pub use execute_change::*; diff --git a/programs/price_based_performance_package/src/lib.rs b/programs/price_based_performance_package/src/lib.rs index 07c95e42..2ca5c838 100644 --- a/programs/price_based_performance_package/src/lib.rs +++ b/programs/price_based_performance_package/src/lib.rs @@ -72,4 +72,9 @@ pub mod price_based_performance_package { ) -> Result<()> { ChangePerformancePackageAuthority::handle(ctx, params) } + + #[access_control(ctx.accounts.validate())] + pub fn burn_performance_package(ctx: Context) -> Result<()> { + BurnPerformancePackage::handle(ctx) + } } diff --git a/scripts/v0.6/burnPerformancePackage.ts b/scripts/v0.6/burnPerformancePackage.ts new file mode 100644 index 00000000..aa1168bc --- /dev/null +++ b/scripts/v0.6/burnPerformancePackage.ts @@ -0,0 +1,87 @@ +import * as anchor from "@coral-xyz/anchor"; +import * as multisig from "@sqds/multisig"; +import { + PRICE_BASED_PERFORMANCE_PACKAGE_PROGRAM_ID, + PriceBasedPerformancePackageClient, + METADAO_MULTISIG_VAULT, +} from "@metadaoproject/futarchy/v0.7"; +import { PublicKey, TransactionMessage } from "@solana/web3.js"; + +// Set the performance package address before running the script +const performancePackage = new PublicKey(""); + +const provider = anchor.AnchorProvider.env(); + +// Payer MUST be a signer with permissions to propose transactions on Metadao DAO's multisig +const payer = provider.wallet["payer"]; + +const priceBasedPerformancePackage: PriceBasedPerformancePackageClient = + new PriceBasedPerformancePackageClient( + provider, + PRICE_BASED_PERFORMANCE_PACKAGE_PROGRAM_ID, + ); + +// We need both the multisig and vault addresses for the Metadao DAO +const metadaoSquadsMultisig = new PublicKey( + "8N3Tvc6B1wEVKVC6iD4s6eyaCNqX2ovj2xze2q3Q9DWH", +); +const metadaoSquadsMultisigVault = METADAO_MULTISIG_VAULT; + +// This should only be run once per DAO/AMM +// It's meant to be a one-off operation that reduces liquidity to a target K (the inital pool's liquidity) and collect it as "fees" +// We're using this because we didn't track LP fee collection in the pool state, nor did we exclude those fees from liquidity +export const burnPerformancePackage = async () => { + const performancePackageAccount = + await priceBasedPerformancePackage.getPerformancePackage( + performancePackage, + ); + + // We call the collect fees instruction from Metadao DAO's multisig account + // It's the only one that can call the collect fees instruction + const metaDaoSquadsMultisigAccount = + await multisig.accounts.Multisig.fromAccountAddress( + anchor.getProvider().connection, + metadaoSquadsMultisig, + ); + + // Prepare transaction message + const burnPerformancePackageIx = + await priceBasedPerformancePackage.program.methods + .burnPerformancePackage() + .accounts({ + performancePackage, + performancePackageTokenVault: + performancePackageAccount.performancePackageTokenVault, + tokenMint: performancePackageAccount.tokenMint, + admin: metadaoSquadsMultisigVault, + spillAccount: payer.publicKey, + }) + .instruction(); + + const transactionMessage = new TransactionMessage({ + instructions: [burnPerformancePackageIx], + payerKey: metadaoSquadsMultisigVault, + recentBlockhash: (await provider.connection.getLatestBlockhash()).blockhash, + }); + + // Create vault transaction + const vaultTxCreateSignature = await multisig.rpc.vaultTransactionCreate({ + connection: anchor.getProvider().connection, + creator: payer.publicKey, + feePayer: payer.publicKey, + ephemeralSigners: 0, + multisigPda: metadaoSquadsMultisig, + transactionIndex: + BigInt(metaDaoSquadsMultisigAccount.transactionIndex.toString()) + 1n, + vaultIndex: 0, + transactionMessage, + }); + + console.log( + "Vault burn performance package transaction create signature:", + vaultTxCreateSignature, + ); + console.log("Go ahead and execute the transaction through Squads."); +}; + +burnPerformancePackage().catch(console.error); diff --git a/scripts/v0.7/burnPerformancePackage.ts b/scripts/v0.7/burnPerformancePackage.ts new file mode 100644 index 00000000..aa1168bc --- /dev/null +++ b/scripts/v0.7/burnPerformancePackage.ts @@ -0,0 +1,87 @@ +import * as anchor from "@coral-xyz/anchor"; +import * as multisig from "@sqds/multisig"; +import { + PRICE_BASED_PERFORMANCE_PACKAGE_PROGRAM_ID, + PriceBasedPerformancePackageClient, + METADAO_MULTISIG_VAULT, +} from "@metadaoproject/futarchy/v0.7"; +import { PublicKey, TransactionMessage } from "@solana/web3.js"; + +// Set the performance package address before running the script +const performancePackage = new PublicKey(""); + +const provider = anchor.AnchorProvider.env(); + +// Payer MUST be a signer with permissions to propose transactions on Metadao DAO's multisig +const payer = provider.wallet["payer"]; + +const priceBasedPerformancePackage: PriceBasedPerformancePackageClient = + new PriceBasedPerformancePackageClient( + provider, + PRICE_BASED_PERFORMANCE_PACKAGE_PROGRAM_ID, + ); + +// We need both the multisig and vault addresses for the Metadao DAO +const metadaoSquadsMultisig = new PublicKey( + "8N3Tvc6B1wEVKVC6iD4s6eyaCNqX2ovj2xze2q3Q9DWH", +); +const metadaoSquadsMultisigVault = METADAO_MULTISIG_VAULT; + +// This should only be run once per DAO/AMM +// It's meant to be a one-off operation that reduces liquidity to a target K (the inital pool's liquidity) and collect it as "fees" +// We're using this because we didn't track LP fee collection in the pool state, nor did we exclude those fees from liquidity +export const burnPerformancePackage = async () => { + const performancePackageAccount = + await priceBasedPerformancePackage.getPerformancePackage( + performancePackage, + ); + + // We call the collect fees instruction from Metadao DAO's multisig account + // It's the only one that can call the collect fees instruction + const metaDaoSquadsMultisigAccount = + await multisig.accounts.Multisig.fromAccountAddress( + anchor.getProvider().connection, + metadaoSquadsMultisig, + ); + + // Prepare transaction message + const burnPerformancePackageIx = + await priceBasedPerformancePackage.program.methods + .burnPerformancePackage() + .accounts({ + performancePackage, + performancePackageTokenVault: + performancePackageAccount.performancePackageTokenVault, + tokenMint: performancePackageAccount.tokenMint, + admin: metadaoSquadsMultisigVault, + spillAccount: payer.publicKey, + }) + .instruction(); + + const transactionMessage = new TransactionMessage({ + instructions: [burnPerformancePackageIx], + payerKey: metadaoSquadsMultisigVault, + recentBlockhash: (await provider.connection.getLatestBlockhash()).blockhash, + }); + + // Create vault transaction + const vaultTxCreateSignature = await multisig.rpc.vaultTransactionCreate({ + connection: anchor.getProvider().connection, + creator: payer.publicKey, + feePayer: payer.publicKey, + ephemeralSigners: 0, + multisigPda: metadaoSquadsMultisig, + transactionIndex: + BigInt(metaDaoSquadsMultisigAccount.transactionIndex.toString()) + 1n, + vaultIndex: 0, + transactionMessage, + }); + + console.log( + "Vault burn performance package transaction create signature:", + vaultTxCreateSignature, + ); + console.log("Go ahead and execute the transaction through Squads."); +}; + +burnPerformancePackage().catch(console.error); diff --git a/sdk/src/v0.6/types/price_based_performance_package.ts b/sdk/src/v0.6/types/price_based_performance_package.ts index 9f0f7d7d..e72df858 100644 --- a/sdk/src/v0.6/types/price_based_performance_package.ts +++ b/sdk/src/v0.6/types/price_based_performance_package.ts @@ -288,6 +288,52 @@ export type PriceBasedPerformancePackage = { }, ]; }, + { + name: "burnPerformancePackage"; + accounts: [ + { + name: "performancePackage"; + isMut: true; + isSigner: false; + }, + { + name: "performancePackageTokenVault"; + isMut: true; + isSigner: false; + }, + { + name: "admin"; + isMut: true; + isSigner: true; + }, + { + name: "spillAccount"; + isMut: true; + isSigner: false; + }, + { + name: "tokenMint"; + isMut: true; + isSigner: false; + }, + { + name: "tokenProgram"; + isMut: false; + isSigner: false; + }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, + ]; + args: []; + }, ]; accounts: [ { @@ -891,6 +937,11 @@ export type PriceBasedPerformancePackage = { name: "InvalidTwapLength"; msg: "TWAP length must be greater than or equal to 1 day and less than 1 year"; }, + { + code: 6013; + name: "InvalidAdmin"; + msg: "Invalid admin"; + }, ]; }; @@ -1184,6 +1235,52 @@ export const IDL: PriceBasedPerformancePackage = { }, ], }, + { + name: "burnPerformancePackage", + accounts: [ + { + name: "performancePackage", + isMut: true, + isSigner: false, + }, + { + name: "performancePackageTokenVault", + isMut: true, + isSigner: false, + }, + { + name: "admin", + isMut: true, + isSigner: true, + }, + { + name: "spillAccount", + isMut: true, + isSigner: false, + }, + { + name: "tokenMint", + isMut: true, + isSigner: false, + }, + { + name: "tokenProgram", + isMut: false, + isSigner: false, + }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, + ], + args: [], + }, ], accounts: [ { @@ -1787,5 +1884,10 @@ export const IDL: PriceBasedPerformancePackage = { name: "InvalidTwapLength", msg: "TWAP length must be greater than or equal to 1 day and less than 1 year", }, + { + code: 6013, + name: "InvalidAdmin", + msg: "Invalid admin", + }, ], }; diff --git a/sdk/src/v0.7/types/price_based_performance_package.ts b/sdk/src/v0.7/types/price_based_performance_package.ts index 9f0f7d7d..e72df858 100644 --- a/sdk/src/v0.7/types/price_based_performance_package.ts +++ b/sdk/src/v0.7/types/price_based_performance_package.ts @@ -288,6 +288,52 @@ export type PriceBasedPerformancePackage = { }, ]; }, + { + name: "burnPerformancePackage"; + accounts: [ + { + name: "performancePackage"; + isMut: true; + isSigner: false; + }, + { + name: "performancePackageTokenVault"; + isMut: true; + isSigner: false; + }, + { + name: "admin"; + isMut: true; + isSigner: true; + }, + { + name: "spillAccount"; + isMut: true; + isSigner: false; + }, + { + name: "tokenMint"; + isMut: true; + isSigner: false; + }, + { + name: "tokenProgram"; + isMut: false; + isSigner: false; + }, + { + name: "eventAuthority"; + isMut: false; + isSigner: false; + }, + { + name: "program"; + isMut: false; + isSigner: false; + }, + ]; + args: []; + }, ]; accounts: [ { @@ -891,6 +937,11 @@ export type PriceBasedPerformancePackage = { name: "InvalidTwapLength"; msg: "TWAP length must be greater than or equal to 1 day and less than 1 year"; }, + { + code: 6013; + name: "InvalidAdmin"; + msg: "Invalid admin"; + }, ]; }; @@ -1184,6 +1235,52 @@ export const IDL: PriceBasedPerformancePackage = { }, ], }, + { + name: "burnPerformancePackage", + accounts: [ + { + name: "performancePackage", + isMut: true, + isSigner: false, + }, + { + name: "performancePackageTokenVault", + isMut: true, + isSigner: false, + }, + { + name: "admin", + isMut: true, + isSigner: true, + }, + { + name: "spillAccount", + isMut: true, + isSigner: false, + }, + { + name: "tokenMint", + isMut: true, + isSigner: false, + }, + { + name: "tokenProgram", + isMut: false, + isSigner: false, + }, + { + name: "eventAuthority", + isMut: false, + isSigner: false, + }, + { + name: "program", + isMut: false, + isSigner: false, + }, + ], + args: [], + }, ], accounts: [ { @@ -1787,5 +1884,10 @@ export const IDL: PriceBasedPerformancePackage = { name: "InvalidTwapLength", msg: "TWAP length must be greater than or equal to 1 day and less than 1 year", }, + { + code: 6013, + name: "InvalidAdmin", + msg: "Invalid admin", + }, ], }; diff --git a/tests/priceBasedPerformancePackage/main.test.ts b/tests/priceBasedPerformancePackage/main.test.ts index 890a3893..a590ae64 100644 --- a/tests/priceBasedPerformancePackage/main.test.ts +++ b/tests/priceBasedPerformancePackage/main.test.ts @@ -4,6 +4,7 @@ import completeUnlock from "./unit/completeUnlock.test.js"; import proposeChange from "./unit/proposeChange.test.js"; import changePerformancePackageAuthority from "./unit/changePerformancePackageAuthority.test.js"; import executeChange from "./unit/executeChange.test.js"; +import burnPerformancePackage from "./unit/burnPerformancePackage.test.js"; export default function suite() { describe("#initialize_performance_package", initializePerformancePackage); @@ -15,4 +16,5 @@ export default function suite() { changePerformancePackageAuthority, ); describe("#execute_change", executeChange); + describe("#burn_performance_package", burnPerformancePackage); } diff --git a/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts b/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts new file mode 100644 index 00000000..b88bb8ac --- /dev/null +++ b/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts @@ -0,0 +1,162 @@ +import { + PublicKey, + Keypair, + Transaction, + SystemProgram, +} from "@solana/web3.js"; +import { assert } from "chai"; +import { mintTo, getAccount } from "spl-token-bankrun"; +import BN from "bn.js"; +import { + getPerformancePackageAddr, + Tranche, +} from "@metadaoproject/futarchy/v0.6"; +import { expectError } from "../../utils.js"; +import { getAssociatedTokenAddress } from "@solana/spl-token"; + +export default function () { + let createKey: Keypair; + let tokenMint: PublicKey; + let tokenAuthority: Keypair; + let tokenAccount: PublicKey; + let recipient: Keypair; + let performancePackage: PublicKey; + let oracleAccount: Keypair; + + beforeEach(async function () { + // Create test accounts + createKey = Keypair.generate(); + tokenAuthority = Keypair.generate(); + recipient = Keypair.generate(); + oracleAccount = Keypair.generate(); + + // Fund accounts with SOL using SystemProgram + const fundingTx = new Transaction().add( + SystemProgram.transfer({ + fromPubkey: this.payer.publicKey, + toPubkey: createKey.publicKey, + lamports: 1000000000, // 1 SOL + }), + SystemProgram.transfer({ + fromPubkey: this.payer.publicKey, + toPubkey: tokenAuthority.publicKey, + lamports: 1000000000, // 1 SOL + }), + SystemProgram.transfer({ + fromPubkey: this.payer.publicKey, + toPubkey: recipient.publicKey, + lamports: 1000000000, // 1 SOL + }), + ); + fundingTx.recentBlockhash = ( + await this.context.banksClient.getLatestBlockhash() + )[0]; + fundingTx.sign(this.payer); + await this.banksClient.processTransaction(fundingTx); + + // Create token mint + tokenMint = await this.createMint(tokenAuthority.publicKey, 6); + + // Create token account + tokenAccount = await this.createTokenAccount( + tokenMint, + tokenAuthority.publicKey, + ); + + // Mint some tokens to the token account + await mintTo( + this.context.banksClient, + this.payer, + tokenMint, + tokenAccount, + tokenAuthority, + 1000000, + ); + + performancePackage = getPerformancePackageAddr({ + createKey: createKey.publicKey, + })[0]; + + let tranches: Tranche[] = [ + { + priceThreshold: new BN(1000000), + tokenAmount: new BN(100000), + }, + { + priceThreshold: new BN(2000000), + tokenAmount: new BN(200000), + }, + ]; + const params = { + tranches, + grantee: recipient.publicKey, + performancePackageAuthority: this.payer.publicKey, + minUnlockTimestamp: new BN( + Number((await this.context.banksClient.getClock()).unixTimestamp) + + 3600, + ), // 1 hour from now + oracleConfig: { + oracleAccount: oracleAccount.publicKey, + byteOffset: 0, + }, + twapLengthSeconds: 86_400, // 1 day + tokenRecipient: recipient.publicKey, + }; + + const tx = await this.priceBasedPerformancePackage + .initializePerformancePackageIx({ + params, + createKey: createKey.publicKey, + tokenMint, + grantorTokenAccount: tokenAccount, + grantor: tokenAuthority.publicKey, + }) + .transaction(); + + tx.recentBlockhash = ( + await this.context.banksClient.getLatestBlockhash() + )[0]; + tx.sign(createKey, this.payer, tokenAuthority); + await this.banksClient.processTransaction(tx); + }); + + it.only("should burn a performance package successfully", async function () { + const performancePackageTokenVault = await getAssociatedTokenAddress( + tokenMint, + performancePackage, + true, + ); + + // Confirm that the performance package and token vault accounts are not closed... yet + let performancePackageAccount = + await this.banksClient.getAccount(performancePackage); + assert.isNotNull(performancePackageAccount); + + let performancePackageTokenVaultAccount = await this.banksClient.getAccount( + performancePackageTokenVault, + ); + assert.isNotNull(performancePackageTokenVaultAccount); + + // Burn the performance package + await this.priceBasedPerformancePackage.program.methods + .burnPerformancePackage() + .accounts({ + performancePackage, + performancePackageTokenVault, + tokenMint, + spillAccount: this.payer.publicKey, + admin: this.payer.publicKey, // This should be the MetaDAO operational multisig vault in production + }) + .rpc(); + + // Confirm that the performance package and token vault accounts are closed + performancePackageAccount = + await this.banksClient.getAccount(performancePackage); + assert.isNull(performancePackageAccount); + + performancePackageTokenVaultAccount = await this.banksClient.getAccount( + performancePackageTokenVault, + ); + assert.isNull(performancePackageTokenVaultAccount); + }); +} From 0d97319f32ca34e3ddfbd2d3dab919174c962a6a Mon Sep 17 00:00:00 2001 From: Pileks Date: Fri, 2 Jan 2026 18:10:05 +0100 Subject: [PATCH 2/4] remove .only from test --- .../unit/burnPerformancePackage.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts b/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts index b88bb8ac..fac30cd5 100644 --- a/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts +++ b/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts @@ -120,7 +120,7 @@ export default function () { await this.banksClient.processTransaction(tx); }); - it.only("should burn a performance package successfully", async function () { + it("should burn a performance package successfully", async function () { const performancePackageTokenVault = await getAssociatedTokenAddress( tokenMint, performancePackage, From ab4c4e52f851973a68a0a212bcba551f1a3aa015 Mon Sep 17 00:00:00 2001 From: Pileks Date: Thu, 8 Jan 2026 02:08:40 +0100 Subject: [PATCH 3/4] add production feature to price based performance package build --- .github/workflows/deploy-programs.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-programs.yaml b/.github/workflows/deploy-programs.yaml index cb1af3da..b23bd8ea 100644 --- a/.github/workflows/deploy-programs.yaml +++ b/.github/workflows/deploy-programs.yaml @@ -90,6 +90,7 @@ jobs: upload_idl: true verify: true use-squads: true + features: "production" priority-fee: ${{ inputs.priority-fee }} secrets: MAINNET_SOLANA_DEPLOY_URL: ${{ secrets.MAINNET_SOLANA_DEPLOY_URL }} From 5656c60ee14ee171abc7aafaa630bec75a9a6e19 Mon Sep 17 00:00:00 2001 From: Pileks Date: Thu, 8 Jan 2026 02:20:54 +0100 Subject: [PATCH 4/4] remove performance package token account close --- .../src/instructions/burn_performance_package.rs | 13 ------------- .../unit/burnPerformancePackage.test.ts | 7 +------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/programs/price_based_performance_package/src/instructions/burn_performance_package.rs b/programs/price_based_performance_package/src/instructions/burn_performance_package.rs index 038f6adc..1cc5df46 100644 --- a/programs/price_based_performance_package/src/instructions/burn_performance_package.rs +++ b/programs/price_based_performance_package/src/instructions/burn_performance_package.rs @@ -82,19 +82,6 @@ impl BurnPerformancePackage<'_> { )?; } - token::close_account(CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::CloseAccount { - account: ctx - .accounts - .performance_package_token_vault - .to_account_info(), - destination: ctx.accounts.spill_account.to_account_info(), - authority: ctx.accounts.performance_package.to_account_info(), - }, - signer, - ))?; - // Performance package account gets closed using close constraint Ok(()) diff --git a/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts b/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts index fac30cd5..795512fb 100644 --- a/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts +++ b/tests/priceBasedPerformancePackage/unit/burnPerformancePackage.test.ts @@ -149,14 +149,9 @@ export default function () { }) .rpc(); - // Confirm that the performance package and token vault accounts are closed + // Confirm that the performance package account is closed performancePackageAccount = await this.banksClient.getAccount(performancePackage); assert.isNull(performancePackageAccount); - - performancePackageTokenVaultAccount = await this.banksClient.getAccount( - performancePackageTokenVault, - ); - assert.isNull(performancePackageTokenVaultAccount); }); }