Skip to content

Commit

Permalink
feat(vault_transaction_accounts_close): instruction, sdk, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vovacodes committed Nov 20, 2023
1 parent 4bdff43 commit 5819c4b
Show file tree
Hide file tree
Showing 15 changed files with 2,328 additions and 855 deletions.
4 changes: 0 additions & 4 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ wallet = "~/.config/solana/id.json"
[test.validator]
url = "https://api.devnet.solana.com"

# Token2022
[[test.validator.clone]]
address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"

[[test.validator.account]]
address = "D3oQ6QxSYk6aKUsmBTa9BghFQvbRi7kxP6h95NSdjjXz"
filename = "tests/fixtures/pre-rent-collector/multisig-account.json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,107 @@ impl ConfigTransactionAccountsClose<'_> {
Ok(())
}
}
// The difference between `VaultTransactionAccountsClose` and `ConfigTransactionAccountsClose`:
// - types: VaultTransactionAccountsClose is for VaultTransaction, obviously;
// - closing conditions for stale txs are a bit more strict for VaultTransactionAccountsClose:
// not all stale transactions can be closed, only the ones that are also non-Approved.
#[derive(Accounts)]
pub struct VaultTransactionAccountsClose<'info> {
#[account(
seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
bump = multisig.bump,
)]
pub multisig: Account<'info, Multisig>,

#[account(mut, close = rent_collector)]
pub proposal: Account<'info, Proposal>,

/// VaultTransaction corresponding to the `proposal`.
#[account(mut, close = rent_collector)]
pub transaction: Account<'info, VaultTransaction>,

/// The rent collector.
/// CHECK: We do the checks in validate().
#[account(mut)]
pub rent_collector: AccountInfo<'info>,

pub system_program: Program<'info, System>,
}

impl VaultTransactionAccountsClose<'_> {
fn validate(&self) -> Result<()> {
let Self {
multisig,
proposal,
transaction,
rent_collector,
..
} = self;

//region multisig

// Has to have `rent_collector` set.
let multisig_rent_collector_key = multisig
.rent_collector
.ok_or(MultisigError::RentReclamationDisabled)?
.key();
//endregion

//region rent_collector

// Has to match the `multisig.rent_collector`.
require_keys_eq!(
multisig_rent_collector_key,
rent_collector.key(),
MultisigError::InvalidRentCollector
);
//endregion

//region proposal

// Has to be for the `multisig`.
require_keys_eq!(
proposal.multisig,
multisig.key(),
MultisigError::ProposalForAnotherMultisig
);

// Has to be in a terminal state or stale and non-Approved,
// because vault transactions still can be executed if they
// were Approved before they became stale.
let is_stale = proposal.transaction_index <= multisig.stale_transaction_index;
let is_approved = matches!(proposal.status, ProposalStatus::Approved { .. });
require!(
proposal.status.is_terminal() || (is_stale && !is_approved),
MultisigError::InvalidProposalStatus
);
//endregion

//region transaction

// Has to be for the `multisig`.
require_keys_eq!(
transaction.multisig,
multisig.key(),
MultisigError::TransactionForAnotherMultisig
);

// Has to be for the `proposal`.
require_eq!(
transaction.index,
proposal.transaction_index,
MultisigError::TransactionForAnotherMultisig
);
//endregion

Ok(())
}

/// Close accounts for vault transactions in terminal states: `Executed`, `Rejected`, or `Cancelled`
/// or non-Approved stale vault transactions.
#[access_control(_ctx.accounts.validate())]
pub fn vault_transaction_accounts_close(_ctx: Context<Self>) -> Result<()> {
// Anchor will close the accounts for us.
Ok(())
}
}
6 changes: 6 additions & 0 deletions programs/squads_multisig_program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,10 @@ pub mod squads_multisig_program {
) -> Result<()> {
ConfigTransactionAccountsClose::config_transaction_accounts_close(ctx)
}

pub fn vault_transaction_accounts_close(
ctx: Context<VaultTransactionAccountsClose>,
) -> Result<()> {
VaultTransactionAccountsClose::vault_transaction_accounts_close(ctx)
}
}
37 changes: 37 additions & 0 deletions sdk/multisig/idl/squads_multisig_program.json
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,43 @@
}
],
"args": []
},
{
"name": "vaultTransactionAccountsClose",
"accounts": [
{
"name": "multisig",
"isMut": false,
"isSigner": false
},
{
"name": "proposal",
"isMut": true,
"isSigner": false
},
{
"name": "transaction",
"isMut": true,
"isSigner": false,
"docs": [
"VaultTransaction corresponding to the `proposal`."
]
},
{
"name": "rentCollector",
"isMut": true,
"isSigner": false,
"docs": [
"The rent collector."
]
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
}
],
"args": []
}
],
"accounts": [
Expand Down
1 change: 1 addition & 0 deletions sdk/multisig/src/generated/instructions/index.ts

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

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

1 change: 1 addition & 0 deletions sdk/multisig/src/instructions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export * from "./proposalCancel.js";
export * from "./proposalCreate.js";
export * from "./proposalReject.js";
export * from "./spendingLimitUse.js";
export * from "./vaultTransactionAccountsClose.js";
export * from "./vaultTransactionCreate.js";
export * from "./vaultTransactionExecute.js";
39 changes: 39 additions & 0 deletions sdk/multisig/src/instructions/vaultTransactionAccountsClose.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { PublicKey } from "@solana/web3.js";
import {
createVaultTransactionAccountsCloseInstruction,
PROGRAM_ID,
} from "../generated";
import { getProposalPda, getTransactionPda } from "../pda";

export function vaultTransactionAccountsClose({
multisigPda,
rentCollector,
transactionIndex,
programId = PROGRAM_ID,
}: {
multisigPda: PublicKey;
rentCollector: PublicKey;
transactionIndex: bigint;
programId?: PublicKey;
}) {
const [proposalPda] = getProposalPda({
multisigPda,
transactionIndex,
programId,
});
const [transactionPda] = getTransactionPda({
multisigPda,
index: transactionIndex,
programId,
});

return createVaultTransactionAccountsCloseInstruction(
{
multisig: multisigPda,
rentCollector,
proposal: proposalPda,
transaction: transactionPda,
},
programId
);
}
1 change: 1 addition & 0 deletions sdk/multisig/src/rpc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export * from "./proposalCancel.js";
export * from "./proposalCreate.js";
export * from "./proposalReject.js";
export * from "./spendingLimitUse.js";
export * from "./vaultTransactionAccountsClose.js";
export * from "./vaultTransactionCreate.js";
export * from "./vaultTransactionExecute.js";
49 changes: 49 additions & 0 deletions sdk/multisig/src/rpc/vaultTransactionAccountsClose.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
Connection,
PublicKey,
SendOptions,
Signer,
TransactionSignature,
} from "@solana/web3.js";
import * as transactions from "../transactions/index.js";
import { translateAndThrowAnchorError } from "../errors";

/**
* Close the Proposal and ConfigTransaction accounts associated with a config transaction.
*/
export async function vaultTransactionAccountsClose({
connection,
feePayer,
multisigPda,
rentCollector,
transactionIndex,
sendOptions,
programId,
}: {
connection: Connection;
feePayer: Signer;
multisigPda: PublicKey;
rentCollector: PublicKey;
transactionIndex: bigint;
sendOptions?: SendOptions;
programId?: PublicKey;
}): Promise<TransactionSignature> {
const blockhash = (await connection.getLatestBlockhash()).blockhash;

const tx = transactions.vaultTransactionAccountsClose({
blockhash,
feePayer: feePayer.publicKey,
rentCollector,
transactionIndex,
multisigPda,
programId,
});

tx.sign([feePayer]);

try {
return await connection.sendTransaction(tx, sendOptions);
} catch (err) {
translateAndThrowAnchorError(err);
}
}
1 change: 1 addition & 0 deletions sdk/multisig/src/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export * from "./proposalCancel.js";
export * from "./proposalCreate.js";
export * from "./proposalReject.js";
export * from "./spendingLimitUse.js";
export * from "./vaultTransactionAccountsClose.js";
export * from "./vaultTransactionCreate.js";
export * from "./vaultTransactionExecute.js";
Loading

0 comments on commit 5819c4b

Please sign in to comment.