Skip to content

Commit

Permalink
Cleaning up SDK, fixing programID bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
blockiosaurus committed Jan 16, 2025
1 parent 6b2d560 commit b6b4adc
Show file tree
Hide file tree
Showing 13 changed files with 7,577 additions and 8,075 deletions.
12,791 changes: 5,986 additions & 6,805 deletions clients/js/pnpm-lock.yaml

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions clients/js/src/generated/instructions/executeCollectionV1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
Serializer,
bytes,
mapSerializer,
publicKey as publicKeySerializer,
struct,
u32,
u8,
Expand All @@ -41,17 +40,17 @@ export type ExecuteCollectionV1InstructionAccounts = {
payer?: Signer;
/** The authority of the collection */
authority?: Signer;
/** The program id of the instruction */
programId?: PublicKey | Pda;
};

// Data.
export type ExecuteCollectionV1InstructionData = {
discriminator: number;
programId: PublicKey;
instructionData: Uint8Array;
};

export type ExecuteCollectionV1InstructionDataArgs = {
programId: PublicKey;
instructionData: Uint8Array;
};

Expand All @@ -67,7 +66,6 @@ export function getExecuteCollectionV1InstructionDataSerializer(): Serializer<
struct<ExecuteCollectionV1InstructionData>(
[
['discriminator', u8()],
['programId', publicKeySerializer()],
['instructionData', bytes({ size: u32() })],
],
{ description: 'ExecuteCollectionV1InstructionData' }
Expand Down Expand Up @@ -117,6 +115,11 @@ export function executeCollectionV1(
isWritable: false as boolean,
value: input.authority ?? null,
},
programId: {
index: 4,
isWritable: false as boolean,
value: input.programId ?? null,
},
} satisfies ResolvedAccountsWithIndices;

// Arguments.
Expand All @@ -131,6 +134,10 @@ export function executeCollectionV1(
if (!resolvedAccounts.payer.value) {
resolvedAccounts.payer.value = context.payer;
}
if (!resolvedAccounts.programId.value) {
resolvedAccounts.programId.value = programId;
resolvedAccounts.programId.isWritable = false;
}

// Accounts in order.
const orderedAccounts: ResolvedAccount[] = Object.values(
Expand Down
19 changes: 12 additions & 7 deletions clients/js/src/generated/instructions/executeV1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
Serializer,
bytes,
mapSerializer,
publicKey as publicKeySerializer,
struct,
u32,
u8,
Expand All @@ -45,19 +44,17 @@ export type ExecuteV1InstructionAccounts = {
authority?: Signer;
/** The system program */
systemProgram?: PublicKey | Pda;
/** The program id of the instruction */
programId?: PublicKey | Pda;
};

// Data.
export type ExecuteV1InstructionData = {
discriminator: number;
programId: PublicKey;
instructionData: Uint8Array;
};

export type ExecuteV1InstructionDataArgs = {
programId: PublicKey;
instructionData: Uint8Array;
};
export type ExecuteV1InstructionDataArgs = { instructionData: Uint8Array };

export function getExecuteV1InstructionDataSerializer(): Serializer<
ExecuteV1InstructionDataArgs,
Expand All @@ -71,7 +68,6 @@ export function getExecuteV1InstructionDataSerializer(): Serializer<
struct<ExecuteV1InstructionData>(
[
['discriminator', u8()],
['programId', publicKeySerializer()],
['instructionData', bytes({ size: u32() })],
],
{ description: 'ExecuteV1InstructionData' }
Expand Down Expand Up @@ -126,6 +122,11 @@ export function executeV1(
isWritable: false as boolean,
value: input.systemProgram ?? null,
},
programId: {
index: 6,
isWritable: false as boolean,
value: input.programId ?? null,
},
} satisfies ResolvedAccountsWithIndices;

// Arguments.
Expand All @@ -147,6 +148,10 @@ export function executeV1(
);
resolvedAccounts.systemProgram.isWritable = false;
}
if (!resolvedAccounts.programId.value) {
resolvedAccounts.programId.value = programId;
resolvedAccounts.programId.isWritable = false;
}

// Accounts in order.
const orderedAccounts: ResolvedAccount[] = Object.values(
Expand Down
159 changes: 82 additions & 77 deletions clients/js/src/instructions/execute.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
Context,
Instruction,
PublicKey,
publicKey,
Signer,
TransactionBuilder,
Expand All @@ -11,110 +13,114 @@ import {
findCollectionSignerPda,
} from '../generated';

export type ExecuteInput = TransactionBuilder | Instruction;

export type ExecuteArgs = Omit<
Parameters<typeof executeV1>[1],
'programId' | 'instructionData'
> & {
builder: TransactionBuilder;
};

export const execute = (
context: Pick<Context, 'payer' | 'programs' | 'eddsa' | 'identity'>,
{ asset, builder, ...args }: ExecuteArgs
) => {
// Create a new builder to store the translated Execute instructions.
let newBuilder = new TransactionBuilder();
// We want to track the signers from the original IXes so they can be added to the Execute instructions.
const signers: Signer[] = [];
// Find the asset signer for the asset.
const [assetSigner] = findAssetSignerPda(context, {
asset: publicKey(asset),
});

// eslint-disable-next-line no-restricted-syntax
for (const ix of builder.items) {
let executeBuilder = newBuilder.add(
// Forward on the original args.
executeV1(context, {
...args,
asset: publicKey(asset),
assetSigner,
// Forward the programID of the instruction being executed.
programId: ix.instruction.programId,
// Forward the data of the instruction being executed.
instructionData: ix.instruction.data,
})
// Add the instruction keys as remaining accounts.
.addRemainingAccounts(
ix.instruction.keys.map((key) => {
// If the key is the asset signer, then we don't want to add it to the Execute instruction
// as a signer because it only gets signed in the CPI.
if (key.pubkey === assetSigner) {
return {
pubkey: key.pubkey,
isSigner: false,
isWritable: key.isWritable,
};
}
return key;
})
)
);
// Capture the builder items so they can be modified.
const executeBuilderItems = executeBuilder.items;
// Add the signers to the Execute instruction.
executeBuilderItems[0].signers.push(
// Add the signers to the Execute instruction, filtering out the asset signer.
...signers.filter((signer) => signer.publicKey !== assetSigner)
);
// Set the modified builder items.
executeBuilder = executeBuilder.setItems(executeBuilderItems);
// Add the Execute instruction to the new builder.
newBuilder = newBuilder.add(executeBuilder);
}

return newBuilder;
builder?: TransactionBuilder;
instruction?: Instruction;
instructions?: Instruction[];
signers?: Signer[];
};

export type ExecuteCollectionArgs = Omit<
Parameters<typeof executeCollectionV1>[1],
'programId' | 'instructionData'
> & {
builder: TransactionBuilder;
builder?: TransactionBuilder;
instruction?: Instruction;
instructions?: Instruction[];
signers?: Signer[];
};

export const execute = (
context: Pick<Context, 'payer' | 'programs' | 'eddsa' | 'identity'>,
args: ExecuteArgs
) => executeCommon(context, args);

export const executeCollection = (
context: Pick<Context, 'payer' | 'programs' | 'eddsa' | 'identity'>,
{ collection, builder, ...args }: ExecuteCollectionArgs
args: ExecuteCollectionArgs
) => executeCommon(context, args);

const executeCommon = (
context: Pick<Context, 'payer' | 'programs' | 'eddsa' | 'identity'>,
args: ExecuteArgs | ExecuteCollectionArgs
) => {
// Create a new builder to store the translated Execute instructions.
let newBuilder = new TransactionBuilder();
let executeBuilder = new TransactionBuilder();
// We want to track the signers from the original IXes so they can be added to the Execute instructions.
const signers: Signer[] = [];
// Find the asset signer for the asset.
const [collectionSigner] = findCollectionSignerPda(context, {
collection: publicKey(collection),
});

let builder: TransactionBuilder = new TransactionBuilder();
if (args.builder) {
builder = args.builder;
} else if (args.instruction) {
builder = new TransactionBuilder().add({
instruction: args.instruction,
signers: args.signers ?? [],
bytesCreatedOnChain: 0,
});
} else if (args.instructions) {
args.instructions.forEach((instruction) => {
const ixSigners: Signer[] = [];
instruction.keys.forEach((key) => {
const signer = signers.find(
(signerKey) => signerKey.publicKey === key.pubkey
);
if (signer) {
ixSigners.push(signer);
}
});
builder = builder.add({
instruction,
signers: ixSigners,
bytesCreatedOnChain: 0,
});
});
} else {
throw new Error('No builder or instruction provided');
}

// eslint-disable-next-line no-restricted-syntax
for (const ix of builder.items) {
let executeBuilder = newBuilder.add(
// Forward on the original args.
executeCollectionV1(context, {
let baseBuilder: TransactionBuilder;
let assetSigner: PublicKey;
if ('asset' in args) {
[assetSigner] = findAssetSignerPda(context, {
asset: publicKey(args.asset),
});
baseBuilder = executeV1(context, {
...args,
collection: publicKey(collection),
collectionSigner,
assetSigner,
// Forward the programID of the instruction being executed.
programId: ix.instruction.programId,
// Forward the data of the instruction being executed.
instructionData: ix.instruction.data,
})
});
} else {
[assetSigner] = findCollectionSignerPda(context, {
collection: publicKey(args.collection),
});
baseBuilder = executeCollectionV1(context, {
...args,
collectionSigner: assetSigner,
// Forward the programID of the instruction being executed.
programId: ix.instruction.programId,
// Forward the data of the instruction being executed.
instructionData: ix.instruction.data,
});
}
executeBuilder = executeBuilder.add(
baseBuilder
// Add the instruction keys as remaining accounts.
.addRemainingAccounts(
ix.instruction.keys.map((key) => {
// If the key is the asset signer, then we don't want to add it to the Execute instruction
// as a signer because it only gets signed in the CPI.
if (key.pubkey === collectionSigner) {
if (key.pubkey === assetSigner) {
return {
pubkey: key.pubkey,
isSigner: false,
Expand All @@ -125,18 +131,17 @@ export const executeCollection = (
})
)
);

// Capture the builder items so they can be modified.
const executeBuilderItems = executeBuilder.items;
// Add the signers to the Execute instruction.
executeBuilderItems[0].signers.push(
// Add the signers to the Execute instruction, filtering out the asset signer.
...signers.filter((signer) => signer.publicKey !== collectionSigner)
...signers.filter((signer) => signer.publicKey !== assetSigner)
);
// Set the modified builder items.
executeBuilder = executeBuilder.setItems(executeBuilderItems);
// Add the Execute instruction to the new builder.
newBuilder = newBuilder.add(executeBuilder);
}

return newBuilder;
return executeBuilder;
};
Loading

0 comments on commit b6b4adc

Please sign in to comment.