Skip to content

Commit

Permalink
feat(rent-reclamation): add member check to batch_accounts_close
Browse files Browse the repository at this point in the history
  • Loading branch information
vovacodes committed Nov 28, 2023
1 parent 5ce68a5 commit 20a1df8
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ impl BatchCreate<'_> {
batch.size = 0;
batch.executed_transaction_index = 0;

batch.invariant()?;

// Updated last transaction index in the multisig account.
multisig.transaction_index = index;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ pub struct BatchAccountsClose<'info> {
)]
pub multisig: Account<'info, Multisig>,

/// Member of the multisig.
pub member: Signer<'info>,

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

Expand Down Expand Up @@ -436,6 +439,15 @@ impl BatchAccountsClose<'_> {
.key();
//endregion

//region member
// Has to be a member of the `multisig`.
// This is checked to prevent potential attackers from closing the `Batch` and `Proposal`
// accounts before all `VaultBatchTransaction`s are closed.
require!(
multisig.is_member(self.member.key()).is_some(),
MultisigError::NotAMember
);

//region rent_collector
// Has to match the `multisig.rent_collector`.
require_keys_eq!(
Expand Down
8 changes: 8 additions & 0 deletions sdk/multisig/idl/squads_multisig_program.json
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,14 @@
"isMut": false,
"isSigner": false
},
{
"name": "member",
"isMut": false,
"isSigner": true,
"docs": [
"Member of the multisig."
]
},
{
"name": "proposal",
"isMut": true,
Expand Down
7 changes: 7 additions & 0 deletions sdk/multisig/src/generated/instructions/batchAccountsClose.ts

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

3 changes: 3 additions & 0 deletions sdk/multisig/src/instructions/batchAccountsClose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import { getProposalPda, getTransactionPda } from "../pda";
*/
export function batchAccountsClose({
multisigPda,
member,
rentCollector,
batchIndex,
programId = PROGRAM_ID,
}: {
multisigPda: PublicKey;
member: PublicKey;
rentCollector: PublicKey;
batchIndex: bigint;
programId?: PublicKey;
Expand All @@ -37,6 +39,7 @@ export function batchAccountsClose({
return createBatchAccountsCloseInstruction(
{
multisig: multisigPda,
member,
rentCollector,
proposal: proposalPda,
batch: batchPda,
Expand Down
5 changes: 4 additions & 1 deletion sdk/multisig/src/rpc/batchAccountsClose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export async function batchAccountsClose({
connection,
feePayer,
multisigPda,
member,
rentCollector,
batchIndex,
sendOptions,
Expand All @@ -30,6 +31,7 @@ export async function batchAccountsClose({
connection: Connection;
feePayer: Signer;
multisigPda: PublicKey;
member: Signer;
rentCollector: PublicKey;
batchIndex: bigint;
sendOptions?: SendOptions;
Expand All @@ -40,13 +42,14 @@ export async function batchAccountsClose({
const tx = transactions.batchAccountsClose({
blockhash,
feePayer: feePayer.publicKey,
member: member.publicKey,
rentCollector,
batchIndex,
multisigPda,
programId,
});

tx.sign([feePayer]);
tx.sign([feePayer, member]);

try {
return await connection.sendTransaction(tx, sendOptions);
Expand Down
3 changes: 3 additions & 0 deletions sdk/multisig/src/transactions/batchAccountsClose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ export function batchAccountsClose({
blockhash,
feePayer,
multisigPda,
member,
rentCollector,
batchIndex,
programId,
}: {
blockhash: string;
feePayer: PublicKey;
multisigPda: PublicKey;
member: PublicKey;
rentCollector: PublicKey;
batchIndex: bigint;
programId?: PublicKey;
Expand All @@ -26,6 +28,7 @@ export function batchAccountsClose({
instructions: [
instructions.batchAccountsClose({
multisigPda,
member,
rentCollector,
batchIndex,
programId,
Expand Down
37 changes: 36 additions & 1 deletion tests/suites/instructions/batchAccountsClose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: Keypair.generate().publicKey,
batchIndex,
programId,
Expand All @@ -168,6 +169,31 @@ describe("Instructions / batch_accounts_close", () => {
);
});

it("error: not a member", async () => {
const batchIndex = testMultisig.rejectedBatchIndex;

const fakeMember = Keypair.generate();

const multisigAccount = await Multisig.fromAccountAddress(
connection,
multisigPda
);

await assert.rejects(
() =>
multisig.rpc.batchAccountsClose({
connection,
feePayer: members.almighty,
multisigPda,
member: fakeMember,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
}),
/Provided pubkey is not a member of multisig/
);
});

it("error: invalid rent_collector", async () => {
const batchIndex = testMultisig.rejectedBatchIndex;

Expand All @@ -179,6 +205,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: fakeRentCollector,
batchIndex,
programId,
Expand Down Expand Up @@ -269,6 +296,7 @@ describe("Instructions / batch_accounts_close", () => {
const ix = multisig.generated.createBatchAccountsCloseInstruction(
{
multisig: multisigPda,
member: members.almighty.publicKey,
rentCollector: vaultPda,
proposal: multisig.getProposalPda({
multisigPda: otherMultisig,
Expand All @@ -292,7 +320,7 @@ describe("Instructions / batch_accounts_close", () => {
instructions: [ix],
}).compileToV0Message();
const tx = new VersionedTransaction(message);
tx.sign([feePayer]);
tx.sign([feePayer, members.almighty]);

await assert.rejects(
() =>
Expand All @@ -317,6 +345,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand All @@ -339,6 +368,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand All @@ -361,6 +391,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand All @@ -381,6 +412,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand Down Expand Up @@ -423,6 +455,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand All @@ -442,6 +475,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand All @@ -461,6 +495,7 @@ describe("Instructions / batch_accounts_close", () => {
connection,
feePayer: members.almighty,
multisigPda,
member: members.almighty,
rentCollector: multisigAccount.rentCollector!,
batchIndex,
programId,
Expand Down

0 comments on commit 20a1df8

Please sign in to comment.