diff --git a/Cargo.lock b/Cargo.lock index f52cbb4..2a3c94b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,10 +30,10 @@ checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2", - "quote", + "proc-macro2 1.0.43", + "quote 1.0.21", "regex", - "syn", + "syn 1.0.99", ] [[package]] @@ -45,10 +45,10 @@ dependencies = [ "anchor-syn", "anyhow", "bs58 0.4.0", - "proc-macro2", - "quote", + "proc-macro2 1.0.43", + "quote 1.0.21", "rustversion", - "syn", + "syn 1.0.99", ] [[package]] @@ -58,8 +58,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" dependencies = [ "anchor-syn", - "proc-macro2", - "syn", + "proc-macro2 1.0.43", + "syn 1.0.99", ] [[package]] @@ -69,9 +69,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" dependencies = [ "anchor-syn", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -82,9 +82,9 @@ checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -96,9 +96,9 @@ dependencies = [ "anchor-syn", "anyhow", "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -109,9 +109,9 @@ checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -122,9 +122,9 @@ checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -135,9 +135,9 @@ checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -173,13 +173,13 @@ dependencies = [ "anyhow", "bs58 0.3.1", "heck", - "proc-macro2", + "proc-macro2 1.0.43", "proc-macro2-diagnostics", - "quote", + "quote 1.0.21", "serde", "serde_json", "sha2 0.9.9", - "syn", + "syn 1.0.99", "thiserror", ] @@ -301,8 +301,8 @@ dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", - "proc-macro2", - "syn", + "proc-macro2 1.0.43", + "syn 1.0.99", ] [[package]] @@ -311,9 +311,9 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -322,9 +322,9 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -370,9 +370,9 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfd2f4180c5721da6335cc9e9061cce522b87a35e51cc57636d28d22a9863c80" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -516,6 +516,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "default-env" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f753eb82d29277e79efc625e84aecacfd4851ee50e05a8573a4740239a77bfd3" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + [[package]] name = "digest" version = "0.9.0" @@ -820,9 +831,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -860,9 +871,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate 1.2.1", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -935,6 +946,15 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + [[package]] name = "proc-macro2" version = "1.0.43" @@ -950,9 +970,9 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "version_check", "yansi", ] @@ -966,13 +986,22 @@ dependencies = [ "squads-mpl", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.43", ] [[package]] @@ -1155,9 +1184,9 @@ version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -1261,10 +1290,10 @@ version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be23cc7a382f54dfe1348edb94610e5cc146b8eb21563cdd04062a403c75ba62" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.43", + "quote 1.0.21", "rustc_version", - "syn", + "syn 1.0.99", ] [[package]] @@ -1323,10 +1352,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d0acbad862093ea123f3a27364336dcb0c8373522cd6810496a34e932c56c1" dependencies = [ "bs58 0.4.0", - "proc-macro2", - "quote", + "proc-macro2 1.0.43", + "quote 1.0.21", "rustversion", - "syn", + "syn 1.0.99", ] [[package]] @@ -1352,9 +1381,10 @@ dependencies = [ [[package]] name = "squads-mpl" -version = "0.1.1" +version = "1.3.0" dependencies = [ "anchor-lang", + "default-env", "hex", "solana-security-txt", ] @@ -1365,14 +1395,25 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + [[package]] name = "syn" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.43", + "quote 1.0.21", "unicode-ident", ] @@ -1382,10 +1423,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", + "unicode-xid 0.2.4", ] [[package]] @@ -1403,9 +1444,9 @@ version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", ] [[package]] @@ -1486,6 +1527,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.4" @@ -1537,9 +1584,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "wasm-bindgen-shared", ] @@ -1549,7 +1596,7 @@ version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ - "quote", + "quote 1.0.21", "wasm-bindgen-macro-support", ] @@ -1559,9 +1606,9 @@ version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1646,8 +1693,8 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", "synstructure", ] diff --git a/idl/program_manager.ts b/idl/program_manager.ts index 49155fe..090fc20 100644 --- a/idl/program_manager.ts +++ b/idl/program_manager.ts @@ -121,6 +121,73 @@ export type ProgramManager = { } ] }, + { + "name": "closeManagedProgramAccount", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "programManager", + "isMut": false, + "isSigner": false + }, + { + "name": "managedProgram", + "isMut": true, + "isSigner": false + }, + { + "name": "transaction", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "closeUpgradeAccount", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "programManager", + "isMut": false, + "isSigner": false + }, + { + "name": "managedProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "programUpgrade", + "isMut": true, + "isSigner": false + }, + { + "name": "transaction", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + } + ], + "args": [] + }, { "name": "setAsExecuted", "accounts": [ @@ -438,6 +505,73 @@ export const IDL: ProgramManager = { } ] }, + { + "name": "closeManagedProgramAccount", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "programManager", + "isMut": false, + "isSigner": false + }, + { + "name": "managedProgram", + "isMut": true, + "isSigner": false + }, + { + "name": "transaction", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "closeUpgradeAccount", + "accounts": [ + { + "name": "multisig", + "isMut": false, + "isSigner": false + }, + { + "name": "programManager", + "isMut": false, + "isSigner": false + }, + { + "name": "managedProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "programUpgrade", + "isMut": true, + "isSigner": false + }, + { + "name": "transaction", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + } + ], + "args": [] + }, { "name": "setAsExecuted", "accounts": [ diff --git a/idl/squads_mpl.ts b/idl/squads_mpl.ts index 6faa198..1e1c6c5 100644 --- a/idl/squads_mpl.ts +++ b/idl/squads_mpl.ts @@ -1,9 +1,12 @@ export type SquadsMpl = { - "version": "0.1.1", + "version": "1.3.0", "name": "squads_mpl", "instructions": [ { "name": "create", + "docs": [ + "Creates a new multisig account" + ], "accounts": [ { "name": "multisig", @@ -44,20 +47,16 @@ export type SquadsMpl = { }, { "name": "addMember", + "docs": [ + "The instruction to add a new member to the multisig.", + "Adds member/key to the multisig and reallocates space if neccessary", + "If the multisig needs to be reallocated, it must be prefunded with", + "enough lamports to cover the new size." + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, - "isSigner": true - }, - { - "name": "member", - "isMut": true, "isSigner": true }, { @@ -80,15 +79,13 @@ export type SquadsMpl = { }, { "name": "removeMember", + "docs": [ + "The instruction to remove a member from the multisig" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -101,15 +98,13 @@ export type SquadsMpl = { }, { "name": "removeMemberAndChangeThreshold", + "docs": [ + "The instruction to change the threshold of the multisig and simultaneously remove a member" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -126,20 +121,13 @@ export type SquadsMpl = { }, { "name": "addMemberAndChangeThreshold", + "docs": [ + "The instruction to change the threshold of the multisig and simultaneously add a member" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, - "isSigner": true - }, - { - "name": "member", - "isMut": true, "isSigner": true }, { @@ -166,15 +154,13 @@ export type SquadsMpl = { }, { "name": "changeThreshold", + "docs": [ + "The instruction to change the threshold of the multisig" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -187,15 +173,17 @@ export type SquadsMpl = { }, { "name": "addAuthority", + "docs": [ + "instruction to increase the authority value tracked in the multisig", + "This is optional, as authorities are simply PDAs, however it may be helpful", + "to keep track of commonly used authorities in a UI.", + "This has no functional impact on the multisig or its functionality, but", + "can be used to track commonly used authorities (ie, vault 1, vault 2, etc.)" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -203,15 +191,13 @@ export type SquadsMpl = { }, { "name": "setExternalExecute", + "docs": [ + "DEPRECATED - constraint has been removed in favor of the roles program" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -224,6 +210,13 @@ export type SquadsMpl = { }, { "name": "createTransaction", + "docs": [ + "Instruction to create a multisig transaction.", + "Each transaction is tied to a single authority, and must be specified when", + "creating the instruction below. authority 0 is reserved for internal", + "instructions, whereas authorities 1 or greater refer to a vault,", + "upgrade authority, or other." + ], "accounts": [ { "name": "multisig", @@ -255,6 +248,10 @@ export type SquadsMpl = { }, { "name": "activateTransaction", + "docs": [ + "Instruction to set the state of a transaction \"active\".", + "\"active\" transactions can then be signed off by multisig members" + ], "accounts": [ { "name": "multisig", @@ -270,17 +267,18 @@ export type SquadsMpl = { "name": "creator", "isMut": true, "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [] }, { "name": "addInstruction", + "docs": [ + "Instruction to attach an instruction to a transaction.", + "Transactions must be in the \"draft\" status, and any", + "signer (aside from execution payer) must match the", + "authority specified during the transaction creation." + ], "accounts": [ { "name": "multisig", @@ -319,6 +317,10 @@ export type SquadsMpl = { }, { "name": "approveTransaction", + "docs": [ + "Instruction to approve a transaction on behalf of a member.", + "The transaction must have an \"active\" status" + ], "accounts": [ { "name": "multisig", @@ -334,17 +336,16 @@ export type SquadsMpl = { "name": "member", "isMut": true, "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [] }, { "name": "rejectTransaction", + "docs": [ + "Instruction to reject a transaction.", + "The transaction must have an \"active\" status." + ], "accounts": [ { "name": "multisig", @@ -360,17 +361,18 @@ export type SquadsMpl = { "name": "member", "isMut": true, "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [] }, { "name": "cancelTransaction", + "docs": [ + "Instruction to cancel a transaction.", + "Transactions must be in the \"executeReady\" status.", + "Transaction will only be cancelled if the number of", + "cancellations reaches the threshold." + ], "accounts": [ { "name": "multisig", @@ -397,6 +399,14 @@ export type SquadsMpl = { }, { "name": "executeTransaction", + "docs": [ + "Instruction to execute a transaction.", + "Transaction status must be \"executeReady\", and the account list must match", + "the unique indexed accounts in the following manner:", + "[ix_1_account, ix_1_program_account, ix_1_remaining_account_1, ix_1_remaining_account_2, ...]", + "", + "Refer to the README for more information on how to construct the account list." + ], "accounts": [ { "name": "multisig", @@ -423,6 +433,19 @@ export type SquadsMpl = { }, { "name": "executeInstruction", + "docs": [ + "instruction to sequentially execute parts of a transaction", + "instructions executed in this matter must be executed in order", + "this may be helpful for processing large batch transfers.", + "", + "NOTE - do not use this instruction if there is not total clarity around", + "potential side effects, as this instruction implies that the approved", + "transaction will be executed partially, and potentially spread out over", + "a period of time. This could introduce problems with state and failed", + "transactions. For example: a program invoked in one of these instructions", + "may be upgraded between executions and potentially make one of the", + "necessary accounts invalid." + ], "accounts": [ { "name": "multisig", @@ -451,6 +474,9 @@ export type SquadsMpl = { "accounts": [ { "name": "ms", + "docs": [ + "Ms is the basic state account for a multisig." + ], "type": { "kind": "struct", "fields": [ @@ -493,6 +519,9 @@ export type SquadsMpl = { }, { "name": "msTransaction", + "docs": [ + "The MsTransaction is the state account for a multisig transaction" + ], "type": { "kind": "struct", "fields": [ @@ -557,6 +586,11 @@ export type SquadsMpl = { }, { "name": "msInstruction", + "docs": [ + "The state account for an instruction that is attached to an instruction.", + "Almost analagous to the native Instruction struct for solana, but with extra", + "field for the bump." + ], "type": { "kind": "struct", "fields": [ @@ -595,6 +629,9 @@ export type SquadsMpl = { "types": [ { "name": "MsAccountMeta", + "docs": [ + "Wrapper for our internal MsInstruction key serialization schema" + ], "type": { "kind": "struct", "fields": [ @@ -615,6 +652,9 @@ export type SquadsMpl = { }, { "name": "IncomingInstruction", + "docs": [ + "Incoming instruction schema, used as an argument in the attach_instruction." + ], "type": { "kind": "struct", "fields": [ @@ -639,6 +679,9 @@ export type SquadsMpl = { }, { "name": "MsTransactionStatus", + "docs": [ + "MsTransactionStatus enum of the current status of the Multisig Transaction." + ], "type": { "kind": "enum", "variants": [ @@ -716,16 +759,23 @@ export type SquadsMpl = { { "code": 6012, "name": "PartialExecution" + }, + { + "code": 6013, + "name": "NotEnoughLamports" } ] }; export const IDL: SquadsMpl = { - "version": "0.1.1", + "version": "1.3.0", "name": "squads_mpl", "instructions": [ { "name": "create", + "docs": [ + "Creates a new multisig account" + ], "accounts": [ { "name": "multisig", @@ -766,20 +816,16 @@ export const IDL: SquadsMpl = { }, { "name": "addMember", + "docs": [ + "The instruction to add a new member to the multisig.", + "Adds member/key to the multisig and reallocates space if neccessary", + "If the multisig needs to be reallocated, it must be prefunded with", + "enough lamports to cover the new size." + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, - "isSigner": true - }, - { - "name": "member", - "isMut": true, "isSigner": true }, { @@ -802,15 +848,13 @@ export const IDL: SquadsMpl = { }, { "name": "removeMember", + "docs": [ + "The instruction to remove a member from the multisig" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -823,15 +867,13 @@ export const IDL: SquadsMpl = { }, { "name": "removeMemberAndChangeThreshold", + "docs": [ + "The instruction to change the threshold of the multisig and simultaneously remove a member" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -848,20 +890,13 @@ export const IDL: SquadsMpl = { }, { "name": "addMemberAndChangeThreshold", + "docs": [ + "The instruction to change the threshold of the multisig and simultaneously add a member" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, - "isSigner": true - }, - { - "name": "member", - "isMut": true, "isSigner": true }, { @@ -888,15 +923,13 @@ export const IDL: SquadsMpl = { }, { "name": "changeThreshold", + "docs": [ + "The instruction to change the threshold of the multisig" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -909,15 +942,17 @@ export const IDL: SquadsMpl = { }, { "name": "addAuthority", + "docs": [ + "instruction to increase the authority value tracked in the multisig", + "This is optional, as authorities are simply PDAs, however it may be helpful", + "to keep track of commonly used authorities in a UI.", + "This has no functional impact on the multisig or its functionality, but", + "can be used to track commonly used authorities (ie, vault 1, vault 2, etc.)" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -925,15 +960,13 @@ export const IDL: SquadsMpl = { }, { "name": "setExternalExecute", + "docs": [ + "DEPRECATED - constraint has been removed in favor of the roles program" + ], "accounts": [ { "name": "multisig", "isMut": true, - "isSigner": false - }, - { - "name": "multisigAuth", - "isMut": true, "isSigner": true } ], @@ -946,6 +979,13 @@ export const IDL: SquadsMpl = { }, { "name": "createTransaction", + "docs": [ + "Instruction to create a multisig transaction.", + "Each transaction is tied to a single authority, and must be specified when", + "creating the instruction below. authority 0 is reserved for internal", + "instructions, whereas authorities 1 or greater refer to a vault,", + "upgrade authority, or other." + ], "accounts": [ { "name": "multisig", @@ -977,6 +1017,10 @@ export const IDL: SquadsMpl = { }, { "name": "activateTransaction", + "docs": [ + "Instruction to set the state of a transaction \"active\".", + "\"active\" transactions can then be signed off by multisig members" + ], "accounts": [ { "name": "multisig", @@ -992,17 +1036,18 @@ export const IDL: SquadsMpl = { "name": "creator", "isMut": true, "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [] }, { "name": "addInstruction", + "docs": [ + "Instruction to attach an instruction to a transaction.", + "Transactions must be in the \"draft\" status, and any", + "signer (aside from execution payer) must match the", + "authority specified during the transaction creation." + ], "accounts": [ { "name": "multisig", @@ -1041,6 +1086,10 @@ export const IDL: SquadsMpl = { }, { "name": "approveTransaction", + "docs": [ + "Instruction to approve a transaction on behalf of a member.", + "The transaction must have an \"active\" status" + ], "accounts": [ { "name": "multisig", @@ -1056,17 +1105,16 @@ export const IDL: SquadsMpl = { "name": "member", "isMut": true, "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [] }, { "name": "rejectTransaction", + "docs": [ + "Instruction to reject a transaction.", + "The transaction must have an \"active\" status." + ], "accounts": [ { "name": "multisig", @@ -1082,17 +1130,18 @@ export const IDL: SquadsMpl = { "name": "member", "isMut": true, "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [] }, { "name": "cancelTransaction", + "docs": [ + "Instruction to cancel a transaction.", + "Transactions must be in the \"executeReady\" status.", + "Transaction will only be cancelled if the number of", + "cancellations reaches the threshold." + ], "accounts": [ { "name": "multisig", @@ -1119,6 +1168,14 @@ export const IDL: SquadsMpl = { }, { "name": "executeTransaction", + "docs": [ + "Instruction to execute a transaction.", + "Transaction status must be \"executeReady\", and the account list must match", + "the unique indexed accounts in the following manner:", + "[ix_1_account, ix_1_program_account, ix_1_remaining_account_1, ix_1_remaining_account_2, ...]", + "", + "Refer to the README for more information on how to construct the account list." + ], "accounts": [ { "name": "multisig", @@ -1145,6 +1202,19 @@ export const IDL: SquadsMpl = { }, { "name": "executeInstruction", + "docs": [ + "instruction to sequentially execute parts of a transaction", + "instructions executed in this matter must be executed in order", + "this may be helpful for processing large batch transfers.", + "", + "NOTE - do not use this instruction if there is not total clarity around", + "potential side effects, as this instruction implies that the approved", + "transaction will be executed partially, and potentially spread out over", + "a period of time. This could introduce problems with state and failed", + "transactions. For example: a program invoked in one of these instructions", + "may be upgraded between executions and potentially make one of the", + "necessary accounts invalid." + ], "accounts": [ { "name": "multisig", @@ -1173,6 +1243,9 @@ export const IDL: SquadsMpl = { "accounts": [ { "name": "ms", + "docs": [ + "Ms is the basic state account for a multisig." + ], "type": { "kind": "struct", "fields": [ @@ -1215,6 +1288,9 @@ export const IDL: SquadsMpl = { }, { "name": "msTransaction", + "docs": [ + "The MsTransaction is the state account for a multisig transaction" + ], "type": { "kind": "struct", "fields": [ @@ -1279,6 +1355,11 @@ export const IDL: SquadsMpl = { }, { "name": "msInstruction", + "docs": [ + "The state account for an instruction that is attached to an instruction.", + "Almost analagous to the native Instruction struct for solana, but with extra", + "field for the bump." + ], "type": { "kind": "struct", "fields": [ @@ -1317,6 +1398,9 @@ export const IDL: SquadsMpl = { "types": [ { "name": "MsAccountMeta", + "docs": [ + "Wrapper for our internal MsInstruction key serialization schema" + ], "type": { "kind": "struct", "fields": [ @@ -1337,6 +1421,9 @@ export const IDL: SquadsMpl = { }, { "name": "IncomingInstruction", + "docs": [ + "Incoming instruction schema, used as an argument in the attach_instruction." + ], "type": { "kind": "struct", "fields": [ @@ -1361,6 +1448,9 @@ export const IDL: SquadsMpl = { }, { "name": "MsTransactionStatus", + "docs": [ + "MsTransactionStatus enum of the current status of the Multisig Transaction." + ], "type": { "kind": "enum", "variants": [ @@ -1438,6 +1528,10 @@ export const IDL: SquadsMpl = { { "code": 6012, "name": "PartialExecution" + }, + { + "code": 6013, + "name": "NotEnoughLamports" } ] }; diff --git a/programs/roles/src/account.rs b/programs/roles/src/account.rs index e34e42e..01b2d82 100644 --- a/programs/roles/src/account.rs +++ b/programs/roles/src/account.rs @@ -371,7 +371,6 @@ impl<'info> ActivateProxy<'info> { multisig: self.multisig.to_account_info(), transaction: self.transaction.to_account_info(), creator: self.delegate.to_account_info(), - system_program: self.system_program.to_account_info(), }; CpiContext::new(cpi_program, cpi_accounts) } @@ -436,7 +435,6 @@ impl<'info> VoteProxy<'info> { multisig: self.multisig.to_account_info(), transaction: self.transaction.to_account_info(), member: self.delegate.to_account_info(), - system_program: self.system_program.to_account_info(), }; CpiContext::new(cpi_program, cpi_accounts) } diff --git a/programs/roles/src/lib.rs b/programs/roles/src/lib.rs index f34699c..0a0b75c 100644 --- a/programs/roles/src/lib.rs +++ b/programs/roles/src/lib.rs @@ -3,7 +3,7 @@ use squads_mpl::errors::MsError; use state::roles::*; pub mod errors; -pub use squads_mpl::state::ms::{Ms, MsInstruction, MsTransaction}; +pub use squads_mpl::state::{Ms, MsInstruction, MsTransaction}; use account::*; pub mod account; pub mod state; diff --git a/programs/squads-mpl/Cargo.toml b/programs/squads-mpl/Cargo.toml index 716c88d..198001c 100644 --- a/programs/squads-mpl/Cargo.toml +++ b/programs/squads-mpl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "squads-mpl" -version = "0.1.1" +version = "1.3.0" description = "Squads Multisig Program Library" authors = ["Sean Lars Ganser ", "Bastien Guillaumat "] homepage = "https://squads.so" @@ -22,5 +22,6 @@ default = [] [dependencies] anchor-lang = "0.26.0" +default-env = "0.1.1" hex = "0.3.1" -solana-security-txt = "1.0.1" \ No newline at end of file +solana-security-txt = "1.0.1" diff --git a/programs/squads-mpl/src/account.rs b/programs/squads-mpl/src/account.rs new file mode 100644 index 0000000..8e27a55 --- /dev/null +++ b/programs/squads-mpl/src/account.rs @@ -0,0 +1,405 @@ +/* + Squads Multisig Program - Account contexts + https://github.com/squads-protocol/squads-mpl +*/ + +use anchor_lang::prelude::*; +use crate::state::*; +use crate::errors::*; + +/// The create multisig account context +/// Expects the following accounts: +/// 1. multisig account +/// 2. creator account [signer] +/// 3. system program +/// +/// Expects the following arguments: +/// 1. threshold: u16 +/// 2. create_key: Pubkey +/// 3. members: Vec +/// 4. meta: String (for optional on-chain memo) +#[derive(Accounts)] +#[instruction(threshold: u16, create_key: Pubkey, members: Vec, meta: String)] +pub struct Create<'info> { + #[account( + init, + payer = creator, + space = Ms::SIZE_WITHOUT_MEMBERS + (members.len() * 32), + seeds = [b"squad", create_key.as_ref(), b"multisig"], bump + )] + pub multisig: Account<'info, Ms>, + + #[account(mut)] + pub creator: Signer<'info>, + pub system_program: Program<'info, System>, +} + +/// The account context for creating a new multisig transaction +/// Upon fresh creation the transaction will be in a Draft state +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. creator account [signer] +/// 4. system program +#[derive(Accounts)] +pub struct CreateTransaction<'info> { + #[account( + mut, + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Account<'info, Ms>, + + #[account( + init, + payer = creator, + space = 8 + MsTransaction::initial_size_with_members(multisig.keys.len()), + seeds = [ + b"squad", + multisig.key().as_ref(), + &multisig.transaction_index.checked_add(1).unwrap().to_le_bytes(), + b"transaction" + ], bump + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + mut, + constraint = multisig.is_member(creator.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub creator: Signer<'info>, + pub system_program: Program<'info, System>, +} + +/// The account context for adding an instruction to a transaction +/// The transaction must be in a Draft state, and the creator must be a member of the multisig +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. instruction account +/// 4. creator account [signer] +/// 5. system program +/// +/// Expects the following arguments: +/// 1. instruction_data: IncomingInstruction +#[derive(Accounts)] +#[instruction(instruction_data: IncomingInstruction)] +pub struct AddInstruction<'info> { + #[account( + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Account<'info, Ms>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + &transaction.transaction_index.to_le_bytes(), + b"transaction" + ], bump = transaction.bump, + constraint = transaction.creator == creator.key(), + constraint = transaction.status == MsTransactionStatus::Draft @MsError::InvalidTransactionState, + constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + init, + payer = creator, + space = 8 + instruction_data.get_max_size(), + seeds = [ + b"squad", + transaction.key().as_ref(), + &transaction.instruction_index.checked_add(1).unwrap().to_le_bytes(), + b"instruction" + ], + bump + )] + pub instruction: Account<'info, MsInstruction>, + + #[account( + mut, + constraint = multisig.is_member(creator.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub creator: Signer<'info>, + pub system_program: Program<'info, System>, +} + +/// The account context for activating a transaction +/// The transaction must be in a Draft state, and the creator must be a member of the multisig +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. creator account [signer] +/// +#[derive(Accounts)] +pub struct ActivateTransaction<'info> { + #[account( + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Account<'info, Ms>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + &transaction.transaction_index.to_le_bytes(), + b"transaction" + ], bump = transaction.bump, + constraint = transaction.creator == creator.key(), + constraint = transaction.status == MsTransactionStatus::Draft @MsError::InvalidTransactionState, + constraint = transaction.transaction_index > multisig.ms_change_index @MsError::DeprecatedTransaction, + constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + mut, + constraint = multisig.is_member(creator.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub creator: Signer<'info>, + // pub system_program: Program<'info, System>, +} + +/// The account context for voting on a transaction +/// The transaction must be in an Active state, and the voter must be a member of the multisig +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. voter account [signer] +/// +#[derive(Accounts)] +pub struct VoteTransaction<'info> { + #[account( + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Account<'info, Ms>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + &transaction.transaction_index.to_le_bytes(), + b"transaction" + ], bump = transaction.bump, + constraint = transaction.status == MsTransactionStatus::Active @MsError::InvalidTransactionState, + constraint = transaction.transaction_index > multisig.ms_change_index @MsError::DeprecatedTransaction, + constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + mut, + constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub member: Signer<'info>, + // pub system_program: Program<'info, System>, +} + +/// The account context for submitting a vote to cancel a transaction +/// The transaction must be in an ExecuteReady state, and the voter must be a member of the multisig +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. member account [signer] +/// +#[derive(Accounts)] +pub struct CancelTransaction<'info> { + #[account( + mut, + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Account<'info, Ms>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + &transaction.transaction_index.to_le_bytes(), + b"transaction" + ], bump = transaction.bump, + constraint = transaction.status == MsTransactionStatus::ExecuteReady @MsError::InvalidTransactionState, + constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + mut, + constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub member: Signer<'info>, + pub system_program: Program<'info, System>, +} + +/// The account context for executing a transaction +/// The transaction must be in an ExecuteReady state, and the creator must be a member of the multisig +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. member account [signer] +/// +#[derive(Accounts)] +pub struct ExecuteTransaction<'info> { + #[account( + mut, + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Box>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + &transaction.transaction_index.to_le_bytes(), + b"transaction" + ], bump = transaction.bump, + constraint = transaction.status == MsTransactionStatus::ExecuteReady @MsError::InvalidTransactionState, + constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, + // if they've already started sequential execution, they must continue + constraint = transaction.executed_index < 1 @MsError::PartialExecution, + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + mut, + constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub member: Signer<'info>, +} + +/// The account context for executing a transaction instruction individually +/// The transaction must be in an ExecuteReady state, and the creator must be a member of the multisig, and the instruction must correlate to the next executed index +/// +/// Expects the following accounts: +/// 1. multisig account +/// 2. transaction account +/// 3. member account [signer] +/// +#[derive(Accounts)] +pub struct ExecuteInstruction<'info> { + #[account( + mut, + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], + bump = multisig.bump, + )] + pub multisig: Box>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + &transaction.transaction_index.to_le_bytes(), + b"transaction" + ], bump = transaction.bump, + constraint = transaction.status == MsTransactionStatus::ExecuteReady @MsError::InvalidTransactionState, + constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, + )] + pub transaction: Account<'info, MsTransaction>, + + #[account( + mut, + seeds = [ + b"squad", + transaction.key().as_ref(), + &transaction.executed_index.checked_add(1).unwrap().to_le_bytes(), + b"instruction" + ], bump = instruction.bump, + // it should be the next expected instruction account to be executed + constraint = instruction.instruction_index == transaction.executed_index.checked_add(1).unwrap() @MsError::InvalidInstructionAccount, + )] + pub instruction: Account<'info, MsInstruction>, + + #[account( + mut, + constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, + )] + pub member: Signer<'info>, +} + +/// The account context for executing an internal multisig transaction (which changes the multisig account) +/// +/// Expects the following accounts: +/// 1. multisig account [signer] +#[derive(Accounts)] +pub struct MsAuth<'info> { + #[account( + mut, + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], bump = multisig.bump, + signer + )] + pub multisig: Box>, +} + +/// The account context for reallocating the multisig account (for add member, where the size may need to be adjusted) +/// +/// Expects the following accounts: +/// 1. multisig account [signer] +/// 2. rent sysvar +/// 3. system program +/// +/// +#[derive(Accounts)] +pub struct MsAuthRealloc<'info> { + #[account( + mut, + seeds = [ + b"squad", + multisig.create_key.as_ref(), + b"multisig" + ], bump = multisig.bump, + signer + )] + pub multisig: Box>, + + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} diff --git a/programs/squads-mpl/src/errors.rs b/programs/squads-mpl/src/errors.rs index 35e1de8..99317d1 100644 --- a/programs/squads-mpl/src/errors.rs +++ b/programs/squads-mpl/src/errors.rs @@ -1,3 +1,8 @@ +/* + Squads Multisig Program - Program Errors + https://github.com/squads-protocol/squads-mpl +*/ + use anchor_lang::prelude::*; #[error_code] diff --git a/programs/squads-mpl/src/lib.rs b/programs/squads-mpl/src/lib.rs index 2daccaa..8471ee5 100644 --- a/programs/squads-mpl/src/lib.rs +++ b/programs/squads-mpl/src/lib.rs @@ -1,3 +1,8 @@ +/* + Squads Multisig Program - Program & Instructions + https://github.com/squads-protocol/squads-mpl +*/ + use anchor_lang::{ prelude::*, solana_program::{ @@ -8,13 +13,16 @@ use anchor_lang::{ use hex::FromHex; -use state::ms::*; -pub mod state; - +use state::*; use errors::*; +use account::*; + +pub mod state; +pub mod account; pub mod errors; -use solana_security_txt::security_txt; +#[cfg(not(feature = "no-entrypoint"))] +use {default_env::default_env, solana_security_txt::security_txt}; #[cfg(not(feature = "no-entrypoint"))] security_txt! { @@ -24,6 +32,7 @@ security_txt! { policy: "https://github.com/Squads-Protocol/squads-mpl/blob/main/SECURITY.md", preferred_languages: "en", source_code: "https://github.com/squads-protocol/squads-mpl", + source_revision: default_env!("GITHUB_SHA", ""), auditors: "OtterSec" } @@ -36,6 +45,7 @@ pub mod squads_mpl { use super::*; + /// Creates a new multisig account // instruction to create a multisig pub fn create( ctx: Context, @@ -73,7 +83,10 @@ pub mod squads_mpl { ) } - // instruction to add a member/key to the multisig and reallocate space if neccessary + /// The instruction to add a new member to the multisig. + /// Adds member/key to the multisig and reallocates space if neccessary + /// If the multisig needs to be reallocated, it must be prefunded with + /// enough lamports to cover the new size. pub fn add_member(ctx: Context, new_member: Pubkey) -> Result<()> { // if max is already reached, we can't have more members if ctx.accounts.multisig.keys.len() >= usize::from(u16::MAX) { @@ -110,7 +123,7 @@ pub mod squads_mpl { ctx.accounts.multisig.set_change_index(new_index) } - // instruction to remove a member/key from the multisig + /// The instruction to remove a member from the multisig pub fn remove_member(ctx: Context, old_member: Pubkey) -> Result<()> { // if there is only one key in this multisig, reject the removal if ctx.accounts.multisig.keys.len() == 1 { @@ -128,7 +141,7 @@ pub mod squads_mpl { ctx.accounts.multisig.set_change_index(new_index) } - // instruction to remove a member/key from the multisig and change the threshold + /// The instruction to change the threshold of the multisig and simultaneously remove a member pub fn remove_member_and_change_threshold<'info>( ctx: Context<'_, '_, '_, 'info, MsAuth<'info>>, old_member: Pubkey, @@ -146,7 +159,7 @@ pub mod squads_mpl { change_threshold(ctx, new_threshold) } - // instruction to add a member/key from the multisig and change the threshold + /// The instruction to change the threshold of the multisig and simultaneously add a member pub fn add_member_and_change_threshold<'info>( ctx: Context<'_, '_, '_, 'info, MsAuthRealloc<'info>>, new_member: Pubkey, @@ -177,7 +190,7 @@ pub mod squads_mpl { ctx.accounts.multisig.set_change_index(new_index) } - // instruction to change the threshold + /// The instruction to change the threshold of the multisig pub fn change_threshold(ctx: Context, new_threshold: u16) -> Result<()> { // if the new threshold value is valid if ctx.accounts.multisig.keys.len() < usize::from(new_threshold) { @@ -193,27 +206,29 @@ pub mod squads_mpl { ctx.accounts.multisig.set_change_index(new_index) } - // instruction to increase the authority value tracked in the multisig - // This is optional, as authorities are simply PDAs, however it may be helpful - // to keep track of commonly used authorities in a UI. + /// instruction to increase the authority value tracked in the multisig + /// This is optional, as authorities are simply PDAs, however it may be helpful + /// to keep track of commonly used authorities in a UI. + /// This has no functional impact on the multisig or its functionality, but + /// can be used to track commonly used authorities (ie, vault 1, vault 2, etc.) pub fn add_authority(ctx: Context) -> Result<()> { ctx.accounts.multisig.add_authority() } - // deprecated! constraint has been removed in favor of the roles program + /// DEPRECATED - constraint has been removed in favor of the roles program // instruction to change the external execute setting, which allows // non-members or programs to execute a transaction. - pub fn set_external_execute(ctx: Context, _setting: bool) -> Result<()> { - let _ms = &mut ctx.accounts.multisig; + pub fn set_external_execute(_ctx: Context, _setting: bool) -> Result<()> { + // let _ms = &mut ctx.accounts.multisig; // ms.allow_external_execute = setting; // no op Ok(()) } - // instruction to create a transaction - // each transaction is tied to a single authority, and must be specified when - // creating the instruction below. authority 0 is reserved for internal - // instructions, whereas authorities 1 or greater refer to a vault, - // upgrade authority, or other. + /// Instruction to create a multisig transaction. + /// Each transaction is tied to a single authority, and must be specified when + /// creating the instruction below. authority 0 is reserved for internal + /// instructions, whereas authorities 1 or greater refer to a vault, + /// upgrade authority, or other. pub fn create_transaction(ctx: Context, authority_index: u32) -> Result<()> { let ms = &mut ctx.accounts.multisig; let authority_bump = match authority_index { @@ -243,16 +258,16 @@ pub mod squads_mpl { ) } - // instruction to set the state of a transaction "active" - // "active" transactions can then be signed off by multisig members + /// Instruction to set the state of a transaction "active". + /// "active" transactions can then be signed off by multisig members pub fn activate_transaction(ctx: Context) -> Result<()> { ctx.accounts.transaction.activate() } - // instruction to attach an instruction to a transaction - // transactions must be in the "draft" status, and any - // signer (aside from execution payer) must math the - // authority specified during the transaction creation + /// Instruction to attach an instruction to a transaction. + /// Transactions must be in the "draft" status, and any + /// signer (aside from execution payer) must match the + /// authority specified during the transaction creation. pub fn add_instruction( ctx: Context, incoming_instruction: IncomingInstruction, @@ -270,8 +285,8 @@ pub mod squads_mpl { ) } - // instruction to approve a transaction on behalf of a member - // the transaction must have an "active" status + /// Instruction to approve a transaction on behalf of a member. + /// The transaction must have an "active" status pub fn approve_transaction(ctx: Context) -> Result<()> { // if they have previously voted to reject, remove that item (change vote check) if let Some(ind) = ctx @@ -299,8 +314,8 @@ pub mod squads_mpl { Ok(()) } - // instruction to reject a transaction - // the transaction must have an "active" status + /// Instruction to reject a transaction. + /// The transaction must have an "active" status. pub fn reject_transaction(ctx: Context) -> Result<()> { // if they have previously voted to approve, remove that item (change vote check) if let Some(ind) = ctx @@ -336,8 +351,10 @@ pub mod squads_mpl { Ok(()) } - // instruction to cancel a transaction - // transactions must be in the "executeReady" status + /// Instruction to cancel a transaction. + /// Transactions must be in the "executeReady" status. + /// Transaction will only be cancelled if the number of + /// cancellations reaches the threshold. pub fn cancel_transaction(ctx: Context) -> Result<()> { // check if they haven't cancelled yet if ctx @@ -357,8 +374,12 @@ pub mod squads_mpl { Ok(()) } - // instruction to execute a transaction - // transaction status must be "executeReady" + /// Instruction to execute a transaction. + /// Transaction status must be "executeReady", and the account list must match + /// the unique indexed accounts in the following manner: + /// [ix_1_account, ix_1_program_account, ix_1_remaining_account_1, ix_1_remaining_account_2, ...] + /// + /// Refer to the README for more information on how to construct the account list. pub fn execute_transaction<'info>( ctx: Context<'_, '_, '_, 'info, ExecuteTransaction<'info>>, account_list: Vec, @@ -401,7 +422,7 @@ pub mod squads_mpl { // iterator for remaining accounts let ix_iter = &mut mapped_remaining_accounts.iter(); - (1..=ctx.accounts.transaction.instruction_index).try_for_each(|i| { + (1..=ctx.accounts.transaction.instruction_index).try_for_each(|i: u8| { // each ix block starts with the ms_ix account let ms_ix_account: &AccountInfo = next_account_info(ix_iter)?; @@ -437,11 +458,11 @@ pub mod squads_mpl { let ix_keys = ms_ix.keys.clone(); // create the instruction to invoke from the saved ms ix account - let ix: Instruction = Instruction::from(ms_ix.clone()); - let mut ix_account_infos: Vec = Vec::::new(); + let ix: Instruction = Instruction::from(ms_ix); + let mut ix_account_infos: Vec = vec![ix_program_info.clone()]; // add the program account needed for the ix - ix_account_infos.push(ix_program_info.clone()); + // ix_account_infos.push(ix_program_info.clone()); // loop through the provided remaining accounts for account_index in 0..ix_keys.len() { @@ -479,7 +500,8 @@ pub mod squads_mpl { }; Ok(()) })?; - + // set the executed index + ctx.accounts.transaction.executed_index = ctx.accounts.transaction.instruction_index; // mark it as executed ctx.accounts.transaction.set_executed()?; // reload any multisig changes @@ -487,17 +509,17 @@ pub mod squads_mpl { Ok(()) } - // instruction to sequentially execute parts of a transaction - // instructions executed in this matter must be executed in order - // this may be helpful for processing large batch transfers. - // - // NOTE - do not use this instruction if there is not total clarity around - // potential side effects, as this instruction implies that the approved - // transaction will be executed partially, and potentially spread out over - // a period of time. This could introduce problems with state and failed - // transactions. For example: a program invoked in one of these instructions - // may be upgraded between executions and potentially make one of the - // necessary accounts invalid. + /// instruction to sequentially execute parts of a transaction + /// instructions executed in this matter must be executed in order + /// this may be helpful for processing large batch transfers. + /// + /// NOTE - do not use this instruction if there is not total clarity around + /// potential side effects, as this instruction implies that the approved + /// transaction will be executed partially, and potentially spread out over + /// a period of time. This could introduce problems with state and failed + /// transactions. For example: a program invoked in one of these instructions + /// may be upgraded between executions and potentially make one of the + /// necessary accounts invalid. pub fn execute_instruction<'info>( ctx: Context<'_, '_, '_, 'info, ExecuteInstruction<'info>>, ) -> Result<()> { @@ -570,318 +592,3 @@ pub mod squads_mpl { Ok(()) } } - -#[derive(Accounts)] -#[instruction(threshold: u16, create_key: Pubkey, members: Vec, meta: String)] -pub struct Create<'info> { - #[account( - init, - payer = creator, - space = Ms::SIZE_WITHOUT_MEMBERS + (members.len() * 32), - seeds = [b"squad", create_key.as_ref(), b"multisig"], bump - )] - pub multisig: Account<'info, Ms>, - - #[account(mut)] - pub creator: Signer<'info>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct CreateTransaction<'info> { - #[account( - mut, - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Account<'info, Ms>, - - #[account( - init, - payer = creator, - space = 8 + MsTransaction::initial_size_with_members(multisig.keys.len()), - seeds = [ - b"squad", - multisig.key().as_ref(), - &multisig.transaction_index.checked_add(1).unwrap().to_le_bytes(), - b"transaction" - ], bump - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - mut, - constraint = multisig.is_member(creator.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub creator: Signer<'info>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -#[instruction(instruction_data: IncomingInstruction)] -pub struct AddInstruction<'info> { - #[account( - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Account<'info, Ms>, - - #[account( - mut, - seeds = [ - b"squad", - multisig.key().as_ref(), - &transaction.transaction_index.to_le_bytes(), - b"transaction" - ], bump = transaction.bump, - constraint = transaction.creator == creator.key(), - constraint = transaction.status == MsTransactionStatus::Draft @MsError::InvalidTransactionState, - constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - init, - payer = creator, - space = 8 + instruction_data.get_max_size(), - seeds = [ - b"squad", - transaction.key().as_ref(), - &transaction.instruction_index.checked_add(1).unwrap().to_le_bytes(), - b"instruction" - ], - bump - )] - pub instruction: Account<'info, MsInstruction>, - - #[account( - mut, - constraint = multisig.is_member(creator.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub creator: Signer<'info>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct ActivateTransaction<'info> { - #[account( - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Account<'info, Ms>, - - #[account( - mut, - seeds = [ - b"squad", - multisig.key().as_ref(), - &transaction.transaction_index.to_le_bytes(), - b"transaction" - ], bump = transaction.bump, - constraint = transaction.creator == creator.key(), - constraint = transaction.status == MsTransactionStatus::Draft @MsError::InvalidTransactionState, - constraint = transaction.transaction_index > multisig.ms_change_index @MsError::DeprecatedTransaction, - constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - mut, - constraint = multisig.is_member(creator.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub creator: Signer<'info>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct VoteTransaction<'info> { - #[account( - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Account<'info, Ms>, - - #[account( - mut, - seeds = [ - b"squad", - multisig.key().as_ref(), - &transaction.transaction_index.to_le_bytes(), - b"transaction" - ], bump = transaction.bump, - constraint = transaction.status == MsTransactionStatus::Active @MsError::InvalidTransactionState, - constraint = transaction.transaction_index > multisig.ms_change_index @MsError::DeprecatedTransaction, - constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - mut, - constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub member: Signer<'info>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct CancelTransaction<'info> { - #[account( - mut, - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Account<'info, Ms>, - - #[account( - mut, - seeds = [ - b"squad", - multisig.key().as_ref(), - &transaction.transaction_index.to_le_bytes(), - b"transaction" - ], bump = transaction.bump, - constraint = transaction.status == MsTransactionStatus::ExecuteReady @MsError::InvalidTransactionState, - constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - mut, - constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub member: Signer<'info>, - pub system_program: Program<'info, System>, -} - -#[derive(Accounts)] -pub struct ExecuteTransaction<'info> { - #[account( - mut, - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Box>, - - #[account( - mut, - seeds = [ - b"squad", - multisig.key().as_ref(), - &transaction.transaction_index.to_le_bytes(), - b"transaction" - ], bump = transaction.bump, - constraint = transaction.status == MsTransactionStatus::ExecuteReady @MsError::InvalidTransactionState, - constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, - // if they've already started sequential execution, they must continue - constraint = transaction.executed_index < 1 @MsError::PartialExecution, - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - mut, - constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub member: Signer<'info>, -} - -// executes the the next instruction sequentially if a tx is executeReady -#[derive(Accounts)] -pub struct ExecuteInstruction<'info> { - #[account( - mut, - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], - bump = multisig.bump, - )] - pub multisig: Box>, - - #[account( - mut, - seeds = [ - b"squad", - multisig.key().as_ref(), - &transaction.transaction_index.to_le_bytes(), - b"transaction" - ], bump = transaction.bump, - constraint = transaction.status == MsTransactionStatus::ExecuteReady @MsError::InvalidTransactionState, - constraint = transaction.ms == multisig.key() @MsError::InvalidInstructionAccount, - )] - pub transaction: Account<'info, MsTransaction>, - - #[account( - mut, - seeds = [ - b"squad", - transaction.key().as_ref(), - &transaction.executed_index.checked_add(1).unwrap().to_le_bytes(), - b"instruction" - ], bump = instruction.bump, - // it should be the next expected instruction account to be executed - constraint = instruction.instruction_index == transaction.executed_index.checked_add(1).unwrap() @MsError::InvalidInstructionAccount, - )] - pub instruction: Account<'info, MsInstruction>, - - #[account( - mut, - constraint = multisig.is_member(member.key()).is_some() @MsError::KeyNotInMultisig, - )] - pub member: Signer<'info>, -} - -#[derive(Accounts)] -pub struct MsAuth<'info> { - #[account( - mut, - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], bump = multisig.bump, - signer - )] - pub multisig: Box>, -} - -#[derive(Accounts)] -pub struct MsAuthRealloc<'info> { - #[account( - mut, - seeds = [ - b"squad", - multisig.create_key.as_ref(), - b"multisig" - ], bump = multisig.bump, - signer - )] - pub multisig: Box>, - - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, -} diff --git a/programs/squads-mpl/src/state/ms.rs b/programs/squads-mpl/src/state.rs similarity index 78% rename from programs/squads-mpl/src/state/ms.rs rename to programs/squads-mpl/src/state.rs index c116576..25f65ab 100644 --- a/programs/squads-mpl/src/state/ms.rs +++ b/programs/squads-mpl/src/state.rs @@ -1,13 +1,19 @@ +/* + Squads Multisig Program - State accounts + https://github.com/squads-protocol/squads-mpl +*/ + use std::convert::TryInto; use anchor_lang::{prelude::*, solana_program::instruction::Instruction}; use anchor_lang::solana_program::borsh::get_instance_packed_len; +/// Ms is the basic state account for a multisig. #[account] pub struct Ms { pub threshold: u16, // threshold for signatures to execute. - pub authority_index: u16, // index to seed other authorities under this multisig. + pub authority_index: u16, // luxury field to help track how many authorities are currently used. pub transaction_index: u32, // look up and seed reference for transactions. @@ -19,7 +25,7 @@ pub struct Ms { pub create_key: Pubkey, // random key(or not) used to seed the multisig pda. - pub allow_external_execute: bool, // allow non-member keys to execute txs (deprecated). + pub allow_external_execute: bool, // DEPRECATED - allow non-member keys to execute txs pub keys: Vec, // keys of the members/owners of the multisig. } @@ -35,6 +41,7 @@ impl Ms { 1 + // allow external execute 4; // for vec length + /// Initializes the new multisig account pub fn init (&mut self, threshold: u16, create_key: Pubkey, members: Vec, bump: u8) -> Result<()> { self.threshold = threshold; self.keys = members; @@ -47,6 +54,7 @@ impl Ms { Ok(()) } + /// Checks to see if the key is a member of the multisig pub fn is_member(&self, member: Pubkey) -> Option { match self.keys.binary_search(&member) { Ok(ind)=> Some(ind), @@ -54,17 +62,22 @@ impl Ms { } } + /// Updates the change index, deprecating any active/draft transactions + /// that have an index lower than the change index pub fn set_change_index(&mut self, index: u32) -> Result<()>{ self.ms_change_index = index; Ok(()) } - // bumps up the authority tracking index for easy use + /// bumps up the authority tracking index for the multisig. + /// This has no effect on the multisig functionality, but is used + /// to track authorities for clients to use (ie, vault 1, vault 2, program authority 3, etc). pub fn add_authority(&mut self) -> Result<()>{ self.authority_index = self.authority_index.checked_add(1).unwrap(); Ok(()) } + /// Adds a member to the multisig. Is a no-op if the member is already in the multisig. pub fn add_member(&mut self, member: Pubkey) -> Result<()>{ if matches!(self.is_member(member), None) { self.keys.push(member); @@ -73,6 +86,7 @@ impl Ms { Ok(()) } + /// Removes a member from the multisig. Is a no-op if the member is not in the multisig. pub fn remove_member(&mut self, member: Pubkey) -> Result<()>{ if let Some(ind) = self.is_member(member) { self.keys.remove(ind); @@ -83,6 +97,7 @@ impl Ms { Ok(()) } + /// sets the threshold for the multisig. pub fn change_threshold(&mut self, threshold: u16) -> Result<()>{ self.threshold = threshold; Ok(()) @@ -90,7 +105,7 @@ impl Ms { } - +/// MsTransactionStatus enum of the current status of the Multisig Transaction. #[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq)] pub enum MsTransactionStatus { Draft, // Transaction default state @@ -101,7 +116,7 @@ pub enum MsTransactionStatus { Cancelled, // Transaction has been cancelled } - +/// The MsTransaction is the state account for a multisig transaction #[account] pub struct MsTransaction { pub creator: Pubkey, // creator, used to seed pda @@ -134,6 +149,7 @@ impl MsTransaction { MsTransaction::MINIMUM_SIZE + (3 * (4 + (members_len * 32) ) ) } + /// initializes the transaction account pub fn init(&mut self, creator: Pubkey, multisig: Pubkey, transaction_index: u32, bump: u8, authority_index: u32, authority_bump: u8) -> Result<()>{ self.creator = creator; self.ms = multisig; @@ -150,50 +166,51 @@ impl MsTransaction { Ok(()) } - // change status to Active + /// change status to Active pub fn activate(&mut self)-> Result<()>{ self.status = MsTransactionStatus::Active; Ok(()) } - // change status to ExecuteReady + /// change status to ExecuteReady pub fn ready_to_execute(&mut self)-> Result<()>{ self.status = MsTransactionStatus::ExecuteReady; Ok(()) } - // set status to Rejected + /// set status to Rejected pub fn set_rejected(&mut self) -> Result<()>{ self.status = MsTransactionStatus::Rejected; Ok(()) } + /// set status to Cancelled pub fn set_cancelled(&mut self) -> Result<()>{ self.status = MsTransactionStatus::Cancelled; Ok(()) } - // set status to executed + /// set status to executed pub fn set_executed(&mut self) -> Result<()>{ self.status = MsTransactionStatus::Executed; Ok(()) } - // sign to approve a transaction + /// sign to approve a transaction pub fn sign(&mut self, member: Pubkey) -> Result<()>{ self.approved.push(member); self.approved.sort(); Ok(()) } - // sign to reject the transaction + /// sign to reject the transaction pub fn reject(&mut self, member: Pubkey) -> Result<()> { self.rejected.push(member); self.rejected.sort(); Ok(()) } - // sign to cancel the transaction if execute_ready + /// sign to cancel the transaction if execute_ready pub fn cancel(&mut self, member: Pubkey) -> Result<()> { self.cancelled.push(member); self.cancelled.sort(); @@ -201,33 +218,37 @@ impl MsTransaction { } - // check if a user has voted already + /// check if a user has voted already pub fn has_voted(&self, member: Pubkey) -> bool { let approved = self.approved.binary_search(&member).is_ok(); let rejected = self.rejected.binary_search(&member).is_ok(); approved || rejected } - // check if a user has signed to approve + /// check if a user has signed to approve pub fn has_voted_approve(&self, member: Pubkey) -> Option { self.approved.binary_search(&member).ok() } - // check if a use has signed to reject + /// check if a use has signed to reject pub fn has_voted_reject(&self, member: Pubkey) -> Option { self.rejected.binary_search(&member).ok() } - // check if a user has signed to cancel + /// check if a user has signed to cancel pub fn has_cancelled(&self, member: Pubkey) -> Option { self.cancelled.binary_search(&member).ok() } + /// removes the key from the rejected vec based on index. + /// used when changing from rejected to approved pub fn remove_reject(&mut self, index: usize) -> Result<()>{ self.rejected.remove(index); Ok(()) } + /// removes the key from the approved vec based on index + /// used when changing from approved to rejected pub fn remove_approve(&mut self, index: usize) -> Result<()>{ self.approved.remove(index); Ok(()) @@ -235,7 +256,9 @@ impl MsTransaction { } -// the internal instruction schema, similar to Instruction but with extra metadata +/// The state account for an instruction that is attached to an instruction. +/// Almost analagous to the native Instruction struct for solana, but with extra +/// field for the bump. #[account] pub struct MsInstruction { pub program_id: Pubkey, @@ -246,10 +269,10 @@ pub struct MsInstruction { pub executed: bool, // deprecated in favor for executed index in the MsTransaction } -// map the incoming instruction to internal instruction schema impl MsInstruction { pub const MAXIMUM_SIZE: usize = 1280; // no longer used but kept for reference, was previously a client side limitation for sizing. + /// Initializes the instruction account pub fn init(&mut self, instruction_index: u8, incoming_instruction: IncomingInstruction, bump: u8) -> Result<()> { self.bump = bump; self.instruction_index = instruction_index; @@ -260,24 +283,15 @@ impl MsInstruction { Ok(()) } - // deprecated in favor for using the executed_index in the MsTransaction + /// DEPRECATED: sequential execution now relies on the executed_index in the MsTransaction pub fn set_executed(&mut self) -> Result<()> { self.executed = true; Ok(()) } } -impl IncomingInstruction { - pub fn get_max_size(&self) -> usize { - // add three the size to correlate with the saved instruction account - // there are 3 extra bytes in a saved instruction account: index, bump, executed - // this is used to determine how much space the incoming instruction - // will used when saved - return get_instance_packed_len(&self).unwrap_or_default().checked_add(3).unwrap_or_default(); - } -} - impl From for Instruction { + /// Converts the MsInstruction to a native Instruction fn from(instruction: MsInstruction) -> Self { Instruction { program_id: instruction.program_id, @@ -295,6 +309,7 @@ impl From for Instruction { } } +/// Wrapper for our internal MsInstruction key serialization schema // internal AccountMeta serialization schema #[derive(AnchorSerialize,AnchorDeserialize, Copy, Clone)] pub struct MsAccountMeta { @@ -303,10 +318,23 @@ pub struct MsAccountMeta { pub is_writable: bool } +/// Incoming instruction schema, used as an argument in the attach_instruction. // serialization schema for incoming instructions to be attached to transaction #[derive(AnchorSerialize,AnchorDeserialize, Clone)] pub struct IncomingInstruction { pub program_id: Pubkey, pub keys: Vec, pub data: Vec +} + +impl IncomingInstruction { + /// Calculates how much space will be needed to allocate to the instruction + /// to be attached to the transaction. + pub fn get_max_size(&self) -> usize { + // add three the size to correlate with the saved instruction account + // there are 3 extra bytes in a saved instruction account: index, bump, executed + // this is used to determine how much space the incoming instruction + // will used when saved + get_instance_packed_len(&self).unwrap_or_default().checked_add(3).unwrap_or_default() + } } \ No newline at end of file diff --git a/programs/squads-mpl/src/state/mod.rs b/programs/squads-mpl/src/state/mod.rs deleted file mode 100644 index 8a3ae87..0000000 --- a/programs/squads-mpl/src/state/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub use ms::*; -pub mod ms; \ No newline at end of file diff --git a/tests/squads-mpl.ts b/tests/squads-mpl.ts index abde275..8220626 100644 --- a/tests/squads-mpl.ts +++ b/tests/squads-mpl.ts @@ -712,7 +712,7 @@ describe("Programs", function(){ }); }); - describe.skip("Program upgrades", function (){ + describe("Program upgrades", function (){ this.beforeAll(async function(){ console.log('Deploying Program Manager Program'); deployPm(); @@ -955,7 +955,7 @@ describe("Programs", function(){ }); // test suite for the roles program - describe.skip("Roles Program", async function(){ + describe("Roles Program", async function(){ const userWithInitRole = anchor.web3.Keypair.generate(); const userWithVoteRole = anchor.web3.Keypair.generate(); const userWithExecuteRole = anchor.web3.Keypair.generate();