Skip to content

Commit

Permalink
fix(execution): Update execution process for add_member
Browse files Browse the repository at this point in the history
  • Loading branch information
bguillaumat committed Jul 29, 2022
1 parent 2206e10 commit f0165c1
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 130 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

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

247 changes: 129 additions & 118 deletions helpers/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,82 @@
import * as anchor from '@project-serum/anchor';
import { Program } from '@project-serum/anchor';
import { Account } from '@solana/web3.js';
import { SquadsMpl } from '../target/types/squads_mpl';
import { ProgramManager } from '../target/types/program_manager';
import {Program} from '@project-serum/anchor';
import {Account} from '@solana/web3.js';
import {SquadsMpl} from '../target/types/squads_mpl';
import {ProgramManager} from '../target/types/program_manager';

// some TX/IX helper functions
export const createTestTransferTransaction = async (authority: anchor.web3.PublicKey, recipient: anchor.web3.PublicKey, amount = 1000000) => {
return anchor.web3.SystemProgram.transfer(
{
fromPubkey: authority,
lamports: amount,
toPubkey: recipient
}
);
return anchor.web3.SystemProgram.transfer(
{
fromPubkey: authority,
lamports: amount,
toPubkey: recipient
}
);
};

export const createBlankTransaction = async (program: Program<SquadsMpl>, feePayer: anchor.web3.PublicKey) =>{
const {blockhash} = await program.provider.connection.getLatestBlockhash();
const lastValidBlockHeight = await program.provider.connection.getBlockHeight();
export const createBlankTransaction = async (program: Program<SquadsMpl>, feePayer: anchor.web3.PublicKey) => {
const {blockhash} = await program.provider.connection.getLatestBlockhash();
const lastValidBlockHeight = await program.provider.connection.getBlockHeight();

return new anchor.web3.Transaction({
blockhash,
lastValidBlockHeight,
feePayer
});
return new anchor.web3.Transaction({
blockhash,
lastValidBlockHeight,
feePayer
});
};


export const createExecuteTransactionTx = async (program: Program<SquadsMpl>, ms: anchor.web3.PublicKey, tx: anchor.web3.PublicKey, feePayer: anchor.web3.PublicKey) => {
export const createExecuteTransactionTx = async (program: Program<SquadsMpl>, ms: anchor.web3.PublicKey, tx: anchor.web3.PublicKey, feePayer: anchor.web3.PublicKey) => {
const txState = await program.account.msTransaction.fetch(tx);

const ixList = await Promise.all([...new Array(txState.instructionIndex)].map(async (a,i) => {
const ixIndexBN = new anchor.BN(i + 1,10);
const [ixKey] = await getIxPDA(tx, ixIndexBN, program.programId);
const ixAccount= await program.account.msInstruction.fetch(ixKey);
return {pubkey: ixKey, ixItem: ixAccount};
const ixList = await Promise.all([...new Array(txState.instructionIndex)].map(async (a, i) => {
const ixIndexBN = new anchor.BN(i + 1, 10);
const [ixKey] = await getIxPDA(tx, ixIndexBN, program.programId);
const ixAccount = await program.account.msInstruction.fetch(ixKey);
return {pubkey: ixKey, ixItem: ixAccount};
}));

const ixKeysList= ixList.map(({pubkey, ixItem}, ixIndex) => {
const ixKeys: anchor.web3.AccountMeta[] = ixItem.keys as anchor.web3.AccountMeta[];

const formattedKeys = ixKeys.map((ixKey,keyInd) => {
return {
pubkey: ixKey.pubkey,
isSigner: false,
isWritable: ixKey.isWritable
};
});
const ixKeysList = ixList.map(({pubkey, ixItem}, ixIndex) => {
const ixKeys: anchor.web3.AccountMeta[] = ixItem.keys as anchor.web3.AccountMeta[];
const sig = anchor.utils.sha256.hash("global:add_member");
const ixDiscriminator = Buffer.from(sig, "hex");
const data = Buffer.concat([ixDiscriminator.slice(0, 8)]);
const ixData = ixItem.data as any

const formattedKeys = ixKeys.map((ixKey, keyInd) => {
if (ixData.includes(data) && keyInd === 2) {
return {
pubkey: feePayer,
isSigner: false,
isWritable: ixKey.isWritable
};
}
return {
pubkey: ixKey.pubkey,
isSigner: false,
isWritable: ixKey.isWritable
};
});

return [
{pubkey, isSigner: false, isWritable: false},
{pubkey: ixItem.programId, isSigner: false, isWritable: false},
...formattedKeys
];
}).reduce((p,c) => p.concat(c),[])
return [
{pubkey, isSigner: false, isWritable: false},
{pubkey: ixItem.programId, isSigner: false, isWritable: false},
...formattedKeys
];
}).reduce((p, c) => p.concat(c), [])

// [ix ix_account, ix program_id, key1, key2 ...]
const keysUnique = ixKeysList.reduce((prev,curr) => {
const keysUnique = ixKeysList.reduce((prev, curr) => {
const inList = prev.findIndex(a => a.pubkey.toBase58() === curr.pubkey.toBase58());
// if its already in the list, and has same write flag
if ( inList >= 0 && prev[inList].isWritable === curr.isWritable){
if (inList >= 0 && prev[inList].isWritable === curr.isWritable) {
return prev;
}else{
} else {
prev.push({pubkey: curr.pubkey, isWritable: curr.isWritable, isSigner: curr.isSigner});
return prev;
}
},[]);
}, []);

const keyIndexMap = ixKeysList.map(a => {
return keysUnique.findIndex(k => {
Expand All @@ -77,110 +88,110 @@ export const createExecuteTransactionTx = async (program: Program<SquadsMpl>, m
});
// console.log('ix key mapping', keyIndexMap);
const keyIndexMapLengthBN = new anchor.BN(keyIndexMap.length, 10);
const keyIndexMapLengthBuffer = keyIndexMapLengthBN.toArrayLike(Buffer, "le",2);
const keyIndexMapLengthBuffer = keyIndexMapLengthBN.toArrayLike(Buffer, "le", 2);
const keyIndexMapBuffer = Buffer.from(keyIndexMap);

let executeKeys = [
{
pubkey: ms,
isSigner: false,
isWritable: true
},
{
pubkey: tx,
isSigner: false,
isWritable: true,
},
{
pubkey: feePayer,
isSigner: true,
isWritable: true,
}
];
{
pubkey: ms,
isSigner: false,
isWritable: true
},
{
pubkey: tx,
isSigner: false,
isWritable: true,
},
{
pubkey: feePayer,
isSigner: true,
isWritable: true,
}
];
// const keys = executeKeys.concat(ixKeysList);
const keys = executeKeys.concat(keysUnique);
const {blockhash} = await program.provider.connection.getLatestBlockhash();
const lastValidBlockHeight = await program.provider.connection.getBlockHeight();

const executeTx = new anchor.web3.Transaction({
blockhash,
lastValidBlockHeight,
feePayer
});

const sig = anchor.utils.sha256.hash("global:execute_transaction");
const ixDiscriminator = Buffer.from(sig, "hex");

const data = Buffer.concat([ixDiscriminator.slice(0,16), keyIndexMapLengthBuffer, keyIndexMapBuffer]);
const executeIx = await program.methods.executeTransaction(Buffer.from(keyIndexMap))
.accounts({multisig: ms, transaction: tx, member: feePayer})
.instruction();
executeIx.keys = executeIx.keys.concat(keysUnique);
executeTx.add(executeIx);
return executeTx;
const keys = executeKeys.concat(keysUnique);
const {blockhash} = await program.provider.connection.getLatestBlockhash();
const lastValidBlockHeight = await program.provider.connection.getBlockHeight();

const executeTx = new anchor.web3.Transaction({
blockhash,
lastValidBlockHeight,
feePayer
});

const sig = anchor.utils.sha256.hash("global:execute_transaction");
const ixDiscriminator = Buffer.from(sig, "hex");

const data = Buffer.concat([ixDiscriminator.slice(0, 16), keyIndexMapLengthBuffer, keyIndexMapBuffer]);
const executeIx = await program.methods.executeTransaction(Buffer.from(keyIndexMap))
.accounts({multisig: ms, transaction: tx, member: feePayer})
.instruction();
executeIx.keys = executeIx.keys.concat(keysUnique);
executeTx.add(executeIx);
return executeTx;
};

// some PDA helper functions
export const getMsPDA = (create_key: anchor.web3.PublicKey, programId: anchor.web3.PublicKey) => anchor.web3.PublicKey.findProgramAddressSync([
anchor.utils.bytes.utf8.encode("squad"),
create_key.toBuffer(),
anchor.utils.bytes.utf8.encode("multisig")
anchor.utils.bytes.utf8.encode("squad"),
create_key.toBuffer(),
anchor.utils.bytes.utf8.encode("multisig")
], programId);

export const getTxPDA = async (msPDA: anchor.web3.PublicKey, txIndexBN: anchor.BN, programId: anchor.web3.PublicKey) => await anchor.web3.PublicKey.findProgramAddress([
anchor.utils.bytes.utf8.encode("squad"),
msPDA.toBuffer(),
txIndexBN.toBuffer("le",4),
anchor.utils.bytes.utf8.encode("transaction")
anchor.utils.bytes.utf8.encode("squad"),
msPDA.toBuffer(),
txIndexBN.toBuffer("le", 4),
anchor.utils.bytes.utf8.encode("transaction")
], programId);

export const getIxPDA = async(txPDA: anchor.web3.PublicKey, iXIndexBN: anchor.BN, programId: anchor.web3.PublicKey) => await anchor.web3.PublicKey.findProgramAddress([
anchor.utils.bytes.utf8.encode("squad"),
txPDA.toBuffer(),
iXIndexBN.toBuffer("le",1), // note instruction index is an u8 (1 byte)
anchor.utils.bytes.utf8.encode("instruction")
export const getIxPDA = async (txPDA: anchor.web3.PublicKey, iXIndexBN: anchor.BN, programId: anchor.web3.PublicKey) => await anchor.web3.PublicKey.findProgramAddress([
anchor.utils.bytes.utf8.encode("squad"),
txPDA.toBuffer(),
iXIndexBN.toBuffer("le", 1), // note instruction index is an u8 (1 byte)
anchor.utils.bytes.utf8.encode("instruction")
], programId);

export const getAuthorityPDA = async (msPDA: anchor.web3.PublicKey, authorityIndexBN: anchor.BN, programId: anchor.web3.PublicKey) => await anchor.web3.PublicKey.findProgramAddress([
anchor.utils.bytes.utf8.encode("squad"),
msPDA.toBuffer(),
authorityIndexBN.toBuffer("le",4), // note authority index is an u32 (4 byte)
anchor.utils.bytes.utf8.encode("authority")
anchor.utils.bytes.utf8.encode("squad"),
msPDA.toBuffer(),
authorityIndexBN.toBuffer("le", 4), // note authority index is an u32 (4 byte)
anchor.utils.bytes.utf8.encode("authority")
], programId);

// basic helpers
export const getNextTxIndex = async (program: Program<SquadsMpl>, msAddress: anchor.web3.PublicKey) => {
const msState = await program.account.ms.fetch(msAddress);
return msState.transactionIndex + 1;
export const getNextTxIndex = async (program: Program<SquadsMpl>, msAddress: anchor.web3.PublicKey) => {
const msState = await program.account.ms.fetch(msAddress);
return msState.transactionIndex + 1;
};

// program manager helpers
export const getProgramManagerPDA = (msPDA: anchor.web3.PublicKey, programId: anchor.web3.PublicKey) => anchor.web3.PublicKey.findProgramAddressSync([
anchor.utils.bytes.utf8.encode("squad"),
msPDA.toBuffer(),
anchor.utils.bytes.utf8.encode("pmanage")
anchor.utils.bytes.utf8.encode("squad"),
msPDA.toBuffer(),
anchor.utils.bytes.utf8.encode("pmanage")
], programId);

export const getManagedProgramPDA = async (programManagerPDA: anchor.web3.PublicKey, managedProgramIndexBN: anchor.BN, programId: anchor.web3.PublicKey) => await anchor.web3.PublicKey.findProgramAddress([
anchor.utils.bytes.utf8.encode("squad"),
programManagerPDA.toBuffer(),
managedProgramIndexBN.toBuffer("le",4), // note authority index is an u32 (4 byte)
anchor.utils.bytes.utf8.encode("program")
anchor.utils.bytes.utf8.encode("squad"),
programManagerPDA.toBuffer(),
managedProgramIndexBN.toBuffer("le", 4), // note authority index is an u32 (4 byte)
anchor.utils.bytes.utf8.encode("program")
], programId);

export const getProgramUpgradePDA = async (managedProgramPDA: anchor.web3.PublicKey, upgradeIndexBN: anchor.BN, programId: anchor.web3.PublicKey) => await anchor.web3.PublicKey.findProgramAddress([
anchor.utils.bytes.utf8.encode("squad"),
managedProgramPDA.toBuffer(),
upgradeIndexBN.toBuffer("le",4), // note authority index is an u32 (4 byte)
anchor.utils.bytes.utf8.encode("pupgrade")
anchor.utils.bytes.utf8.encode("squad"),
managedProgramPDA.toBuffer(),
upgradeIndexBN.toBuffer("le", 4), // note authority index is an u32 (4 byte)
anchor.utils.bytes.utf8.encode("pupgrade")
], programId);

export const getNextProgramIndex = async (program: Program<ProgramManager>, pmAddress: anchor.web3.PublicKey) => {
const pmState = await program.account.programManager.fetch(pmAddress);
return pmState.managedProgramIndex + 1;
export const getNextProgramIndex = async (program: Program<ProgramManager>, pmAddress: anchor.web3.PublicKey) => {
const pmState = await program.account.programManager.fetch(pmAddress);
return pmState.managedProgramIndex + 1;
};

export const getNextUpgradeIndex = async (program: Program<ProgramManager>, mpAddress: anchor.web3.PublicKey) => {
const mpState = await program.account.managedProgram.fetch(mpAddress);
return mpState.upgradeIndex + 1;
export const getNextUpgradeIndex = async (program: Program<ProgramManager>, mpAddress: anchor.web3.PublicKey) => {
const mpState = await program.account.managedProgram.fetch(mpAddress);
return mpState.upgradeIndex + 1;
};
3 changes: 2 additions & 1 deletion programs/squads-mpl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ cpi = ["no-entrypoint"]
default = []

[dependencies]
anchor-lang = "0.25.0"
anchor-lang = "0.25.0"
hex = "0.3.1"
Loading

0 comments on commit f0165c1

Please sign in to comment.