Skip to content

Commit

Permalink
feat(config_transaction_create): implement sdk and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vovacodes committed Mar 8, 2023
1 parent 74e3cb6 commit 2aa94ab
Show file tree
Hide file tree
Showing 13 changed files with 414 additions and 105 deletions.
8 changes: 5 additions & 3 deletions programs/multisig/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ pub enum MultisigError {
InvalidNumberOfAccounts,
#[msg("Invalid account provided")]
InvalidAccount,
#[msg("transaction_execute reentrancy is forbidden")]
#[msg("`transaction_execute` reentrancy is forbidden")]
ExecuteReentrancy,
#[msg("Cannot remove last member")]
RemoveLastMember,
#[msg("Members don't include any voters")]
NoVoters,
#[msg("`stale_transaction_index` must be <= `transaction_index`")]
InvalidStaleTransactionIndex,
#[msg("instruction not supported for controlled multisig")]
#[msg("Instruction not supported for controlled multisig")]
NotSupportedForControlled,
#[msg("transaction time lock has not been released")]
#[msg("Transaction time lock has not been released")]
TimeLockNotReleased,
#[msg("Config transaction must have at least one action")]
NoActions,
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ pub struct ConfigTransactionCreateArgs {
pub struct ConfigTransactionCreate<'info> {
#[account(
mut,
seeds = [SEED_PREFIX, multisig.create_key.as_ref(), SEED_MULTISIG],
seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
bump = multisig.bump,
constraint = multisig.config_authority != Pubkey::default() @ MultisigError::NotSupportedForControlled,
constraint = multisig.config_authority == Pubkey::default() @ MultisigError::NotSupportedForControlled,
)]
pub multisig: Account<'info, Multisig>,

Expand Down Expand Up @@ -51,6 +51,8 @@ impl ConfigTransactionCreate<'_> {
ctx: Context<Self>,
args: ConfigTransactionCreateArgs,
) -> Result<()> {
require!(!args.actions.is_empty(), MultisigError::NoActions);

let multisig = &mut ctx.accounts.multisig;
let transaction = &mut ctx.accounts.transaction;
let creator = &mut ctx.accounts.creator;
Expand Down
11 changes: 8 additions & 3 deletions sdk/multisig/idl/multisig.json
Original file line number Diff line number Diff line change
Expand Up @@ -1368,7 +1368,7 @@
{
"code": 6014,
"name": "ExecuteReentrancy",
"msg": "transaction_execute reentrancy is forbidden"
"msg": "`transaction_execute` reentrancy is forbidden"
},
{
"code": 6015,
Expand All @@ -1388,12 +1388,17 @@
{
"code": 6018,
"name": "NotSupportedForControlled",
"msg": "instruction not supported for controlled multisig"
"msg": "Instruction not supported for controlled multisig"
},
{
"code": 6019,
"name": "TimeLockNotReleased",
"msg": "transaction time lock has not been released"
"msg": "Transaction time lock has not been released"
},
{
"code": 6020,
"name": "NoActions",
"msg": "Config transaction must have at least one action"
}
],
"metadata": {
Expand Down
32 changes: 26 additions & 6 deletions sdk/multisig/src/generated/errors/index.ts

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

2 changes: 1 addition & 1 deletion sdk/multisig/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export * as rpc from "./rpc.js";
/** Transactions for the multisig program. */
export * as transactions from "./transactions.js";
/** Instructions for the multisig program. */
export * as instructions from "./instructions.js";
export * as instructions from "./instructions/index.js";
/** Additional types */
export * as types from "./types.js";
/** Utils for the multisig program. */
Expand Down
30 changes: 30 additions & 0 deletions sdk/multisig/src/instructions/configTransactionCreate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { PublicKey } from "@solana/web3.js";
import {
ConfigAction,
createConfigTransactionCreateInstruction,
} from "../generated";
import { getTransactionPda } from "../pda";

export function configTransactionCreate({
multisigPda,
creator,
transactionIndex,
actions,
memo,
}: {
multisigPda: PublicKey;
creator: PublicKey;
transactionIndex: bigint;
actions: ConfigAction[];
memo?: string;
}) {
const [transactionPda] = getTransactionPda({
multisigPda,
index: transactionIndex,
});

return createConfigTransactionCreateInstruction(
{ creator, multisig: multisigPda, transaction: transactionPda },
{ args: { actions, memo: memo ?? null } }
);
}
3 changes: 3 additions & 0 deletions sdk/multisig/src/instructions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./configTransactionCreate.js";
export * from "./multisigCreate.js";
export * from "./vaultTransactionExecute.js";
39 changes: 39 additions & 0 deletions sdk/multisig/src/instructions/multisigCreate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
import { createMultisigCreateInstruction, Member } from "../generated";

export function multisigCreate({
creator,
multisigPda,
configAuthority,
threshold,
members,
timeLock,
createKey,
memo,
}: {
creator: PublicKey;
multisigPda: PublicKey;
configAuthority: PublicKey | null;
threshold: number;
members: Member[];
timeLock: number;
createKey: PublicKey;
memo?: string;
}): TransactionInstruction {
return createMultisigCreateInstruction(
{
creator,
createKey,
multisig: multisigPda,
},
{
args: {
configAuthority,
threshold,
members,
timeLock,
memo: memo ?? null,
},
}
);
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,11 @@
import { AccountMeta, Connection, PublicKey } from "@solana/web3.js";
import { getEphemeralSignerPda, getTransactionPda, getVaultPda } from "../pda";
import {
AccountMeta,
Connection,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js";
import invariant from "invariant";
import {
createMultisigCreateInstruction,
createVaultTransactionExecuteInstruction,
createConfigTransactionExecuteInstruction,
Member,
VaultTransaction,
ConfigTransaction,
} from "./generated";
import { getEphemeralSignerPda, getVaultPda, getTransactionPda } from "./pda";
import { isSignerIndex, isStaticWritableIndex } from "./utils";

export function multisigCreate({
creator,
multisigPda,
configAuthority,
threshold,
members,
timeLock,
createKey,
memo,
}: {
creator: PublicKey;
multisigPda: PublicKey;
configAuthority: PublicKey | null;
threshold: number;
members: Member[];
timeLock: number;
createKey: PublicKey;
memo?: string;
}): TransactionInstruction {
return createMultisigCreateInstruction(
{
creator,
createKey,
multisig: multisigPda,
},
{
args: {
configAuthority,
threshold,
members,
timeLock,
memo: memo ?? null,
},
}
);
}
} from "../generated";
import { isSignerIndex, isStaticWritableIndex } from "../utils";
import invariant from "invariant";

export async function vaultTransactionExecute({
connection,
Expand Down
47 changes: 45 additions & 2 deletions sdk/multisig/src/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
TransactionSignature,
} from "@solana/web3.js";
import * as transactions from "./transactions.js";
import { Member } from "./generated";
import { ConfigAction, Member } from "./generated";
import { translateAndThrowAnchorError } from "./errors";

/** Creates a new multisig. */
Expand Down Expand Up @@ -101,7 +101,50 @@ export async function multisigAddMember({
}
}

/** Create a new transaction. */
/** Create a new config transaction. */
export async function configTransactionCreate({
connection,
feePayer,
multisigPda,
transactionIndex,
creator,
actions,
memo,
signers,
sendOptions,
}: {
connection: Connection;
feePayer: Signer;
multisigPda: PublicKey;
transactionIndex: bigint;
creator: PublicKey;
actions: ConfigAction[];
memo?: string;
signers?: Signer[];
sendOptions?: SendOptions;
}): Promise<TransactionSignature> {
const blockhash = (await connection.getLatestBlockhash()).blockhash;

const tx = transactions.configTransactionCreate({
blockhash,
feePayer: feePayer.publicKey,
multisigPda,
transactionIndex,
creator,
actions,
memo,
});

tx.sign([feePayer, ...(signers ?? [])]);

try {
return await connection.sendTransaction(tx, sendOptions);
} catch (err) {
translateAndThrowAnchorError(err);
}
}

/** Create a new vault transaction. */
export async function vaultTransactionCreate({
connection,
feePayer,
Expand Down
Loading

0 comments on commit 2aa94ab

Please sign in to comment.