Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
10f0df9
Draft instruction plans
lorisleiva Mar 28, 2025
b4a0c6b
Merge branch 'main' into loris/ix-plans
lorisleiva Apr 2, 2025
16f8192
wip
lorisleiva Apr 3, 2025
c1216dc
wip
lorisleiva Apr 3, 2025
9eb4660
wip
lorisleiva Apr 3, 2025
7152c2c
wip
lorisleiva Apr 3, 2025
ab649fd
wip
lorisleiva Apr 3, 2025
0f70410
wip
lorisleiva Apr 3, 2025
4b060ca
wip
lorisleiva Apr 3, 2025
963015b
wip
lorisleiva Apr 3, 2025
128bc7b
wip
lorisleiva Apr 3, 2025
0b8e260
wip
lorisleiva Apr 3, 2025
327bde6
wip
lorisleiva Apr 3, 2025
d7d3c8a
wip
lorisleiva Apr 3, 2025
7aeb7b9
wip
lorisleiva Apr 3, 2025
f3587f8
wip
lorisleiva Apr 4, 2025
dd03693
wip
lorisleiva Apr 4, 2025
e6213ee
wip
lorisleiva Apr 4, 2025
bd79ee9
wip
lorisleiva Apr 4, 2025
ddbd604
wip
lorisleiva Apr 4, 2025
aac5d24
Add tests for non-divisible sequential plans
lorisleiva Apr 4, 2025
072383e
wip
lorisleiva Apr 4, 2025
d50ff83
wip
lorisleiva Apr 4, 2025
b75ca48
wip
lorisleiva Apr 4, 2025
5b6e471
wip
lorisleiva Apr 4, 2025
f9c0860
wip
lorisleiva Apr 4, 2025
3d7b052
wip
lorisleiva Apr 4, 2025
f780871
wip
lorisleiva Apr 4, 2025
aa42009
wip
lorisleiva Apr 4, 2025
849aca9
wip
lorisleiva Apr 5, 2025
a4fbb96
wip
lorisleiva Apr 5, 2025
08eb4c9
wip
lorisleiva Apr 5, 2025
b2b9e0e
wip
lorisleiva Apr 5, 2025
fe2990c
wip
lorisleiva Apr 5, 2025
bfaa1d8
wip
lorisleiva Apr 5, 2025
6856500
wip
lorisleiva Apr 5, 2025
4f13f74
wip
lorisleiva Apr 5, 2025
ef9a11c
wip
lorisleiva Apr 5, 2025
1c238ac
wip
lorisleiva Apr 5, 2025
1359611
wip
lorisleiva Apr 5, 2025
47604e3
wip
lorisleiva Apr 5, 2025
1ecf66f
wip
lorisleiva Apr 5, 2025
d573f9c
wip
lorisleiva Apr 5, 2025
5482df8
wip
lorisleiva Apr 5, 2025
8ded5ee
wip
lorisleiva Apr 5, 2025
bcbdc38
wip
lorisleiva Apr 5, 2025
b941c82
wip
lorisleiva Apr 5, 2025
471e06c
wip
lorisleiva Apr 5, 2025
1d74601
wip
lorisleiva Apr 5, 2025
290000e
wip
lorisleiva Apr 6, 2025
56d5cda
wip
lorisleiva Apr 6, 2025
fd2868d
wip
lorisleiva Apr 6, 2025
d4d6389
wip
lorisleiva Apr 6, 2025
a74a411
wip
lorisleiva Apr 6, 2025
8568982
wip
lorisleiva Apr 6, 2025
251788b
wip
lorisleiva Apr 6, 2025
b4f0da5
wip
lorisleiva Apr 6, 2025
2a3ee60
wip
lorisleiva Apr 6, 2025
1228c8b
wip
lorisleiva Apr 7, 2025
2993186
wip
lorisleiva Apr 7, 2025
f1de283
wip
lorisleiva Apr 7, 2025
4a034d1
wip
lorisleiva Apr 7, 2025
4f61855
wip
lorisleiva Apr 7, 2025
d962dd5
wip
lorisleiva Apr 7, 2025
b3a40f0
wip
lorisleiva Apr 7, 2025
82271b6
wip
lorisleiva Apr 8, 2025
09323a3
wip
lorisleiva Apr 8, 2025
192eede
wip
lorisleiva Apr 8, 2025
94af552
wip
lorisleiva Apr 8, 2025
aa5bc8b
wip
lorisleiva Apr 9, 2025
ba39a09
wip
lorisleiva Apr 9, 2025
6b72524
wip
lorisleiva Apr 9, 2025
48f3814
wip
lorisleiva Apr 9, 2025
681a5d3
wip
lorisleiva Apr 9, 2025
201df48
wip
lorisleiva Apr 9, 2025
8aacc6e
wip
lorisleiva Apr 9, 2025
ece7994
Remove estimateAndSetComputeUnitLimitForTransactionPlanner
lorisleiva Apr 9, 2025
c6fcd42
wip
lorisleiva Apr 9, 2025
2750a49
wip
lorisleiva Apr 9, 2025
7215483
wip
lorisleiva Apr 9, 2025
d60e04a
Remove transactionPlannerFactoryDecorators
lorisleiva Apr 9, 2025
797fbd1
Remove TransactionPlannerFactory
lorisleiva Apr 9, 2025
e59df5a
wip
lorisleiva Apr 9, 2025
ffc2cd4
wip
lorisleiva Apr 9, 2025
3877e05
wip
lorisleiva Apr 9, 2025
7064e5c
Simplify TransactionPlanExecutor by removing factories
lorisleiva Apr 9, 2025
04cf8ba
wip
lorisleiva Apr 10, 2025
1d04269
wip
lorisleiva Apr 10, 2025
6c776ae
wip
lorisleiva Apr 10, 2025
3f0d080
wip
lorisleiva Apr 10, 2025
1f4cd04
wip
lorisleiva Apr 10, 2025
54743a8
wip
lorisleiva Apr 10, 2025
69760b0
wip
lorisleiva Apr 10, 2025
d94dcbc
wip
lorisleiva Apr 10, 2025
547ba48
wip
lorisleiva Apr 10, 2025
71ebf24
wip
lorisleiva Apr 10, 2025
59728c0
Throw if created TransactionPlan is invalid
lorisleiva Apr 10, 2025
315482e
wip
lorisleiva Apr 10, 2025
b2e448e
wip
lorisleiva Apr 10, 2025
463d972
wip
lorisleiva Apr 11, 2025
e4e3f6f
wip
lorisleiva Apr 11, 2025
4dd04ae
wip
lorisleiva Apr 11, 2025
47b0c52
wip
lorisleiva Apr 11, 2025
bb70d2d
wip
lorisleiva Apr 11, 2025
7b2723b
wip
lorisleiva Apr 11, 2025
db69ec4
wip
lorisleiva Apr 11, 2025
760d9d9
wip
lorisleiva Apr 11, 2025
bd8e7a5
wip
lorisleiva Apr 11, 2025
a9e1c73
wip
lorisleiva Apr 11, 2025
279865c
wip
lorisleiva Apr 11, 2025
5edbfc0
wip
lorisleiva Apr 11, 2025
1ec0180
wip
lorisleiva Apr 11, 2025
4e7715f
wip
lorisleiva Apr 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 138 additions & 126 deletions clients/js/src/cli.ts

Large diffs are not rendered by default.

227 changes: 91 additions & 136 deletions clients/js/src/createMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,173 +1,128 @@
import { getTransferSolInstruction } from '@solana-program/system';
import {
CompilableTransactionMessage,
GetMinimumBalanceForRentExemptionApi,
Lamports,
ReadonlyUint8Array,
Rpc,
TransactionSigner,
} from '@solana/kit';
import {
getAllocateInstruction,
getInitializeInstruction,
InitializeInput,
PROGRAM_METADATA_PROGRAM_ADDRESS,
} from './generated';
import {
getTransactionMessageFromPlan,
InstructionPlan,
MessageInstructionPlan,
createDefaultTransactionPlanExecutor,
createDefaultTransactionPlanner,
parallelInstructionPlan,
sequentialInstructionPlan,
} from './instructionPlans';
import {
calculateMaxChunkSize,
getComputeUnitInstructions,
getExtendedMetadataInput,
getExtendInstructionPlan,
getMetadataInstructionPlanExecutor,
getPdaDetails,
getWriteInstructionPlan,
messageFitsInOneTransaction,
PdaDetails,
REALLOC_LIMIT,
} from './internals';
import { getAccountSize, MetadataInput, MetadataResponse } from './utils';

export async function createMetadata(
input: MetadataInput
): Promise<MetadataResponse> {
const extendedInput = await getExtendedMetadataInput(input);
const executor = getMetadataInstructionPlanExecutor(extendedInput);
const plan = await getCreateMetadataInstructionPlan(extendedInput);
return await executor(plan);
}

export async function getCreateMetadataInstructionPlan(
input: Omit<MetadataInput, 'rpc' | 'rpcSubscriptions'> &
PdaDetails & {
rpc: Rpc<GetMinimumBalanceForRentExemptionApi>;
defaultMessage: CompilableTransactionMessage;
}
): Promise<InstructionPlan> {
const rent = await input.rpc
.getMinimumBalanceForRentExemption(getAccountSize(input.data.length))
.send();
const planUsingInstructionData =
getCreateMetadataInstructionPlanUsingInstructionData({ ...input, rent });
const messageUsingInstructionData = getTransactionMessageFromPlan(
input.defaultMessage,
planUsingInstructionData
);
const useBuffer =
input.buffer === undefined
? !messageFitsInOneTransaction(messageUsingInstructionData)
: !!input.buffer;

if (!useBuffer) {
return planUsingInstructionData;
input: MetadataInput & {
rpc: Rpc<GetMinimumBalanceForRentExemptionApi> &
Parameters<typeof createDefaultTransactionPlanExecutor>[0]['rpc'];
rpcSubscriptions: Parameters<
typeof createDefaultTransactionPlanExecutor
>[0]['rpcSubscriptions'];
}

const chunkSize = calculateMaxChunkSize(input.defaultMessage, {
...input,
buffer: input.metadata,
): Promise<MetadataResponse> {
const planner = createDefaultTransactionPlanner({
feePayer: input.payer,
computeUnitPrice: input.priorityFees,
});
const executor = createDefaultTransactionPlanExecutor({
rpc: input.rpc,
rpcSubscriptions: input.rpcSubscriptions,
parallelChunkSize: 5,
});
return getCreateMetadataInstructionPlanUsingBuffer({

const [{ programData, isCanonical, metadata }, rent] = await Promise.all([
getPdaDetails(input),
input.rpc
.getMinimumBalanceForRentExemption(getAccountSize(input.data.length))
.send(),
]);
const extendedInput = {
...input,
chunkSize,
programData: isCanonical ? programData : undefined,
metadata,
rent,
});
};

const transactionPlan = await planner(
getCreateMetadataInstructionPlanUsingInstructionData(extendedInput)
).catch(() =>
planner(getCreateMetadataInstructionPlanUsingBuffer(extendedInput))
);

const result = await executor(transactionPlan);
return { metadata, result };
}

export function getCreateMetadataInstructionPlanUsingInstructionData(
input: Omit<MetadataInput, 'rpc' | 'rpcSubscriptions'> &
PdaDetails & { rent: Lamports }
): MessageInstructionPlan {
return {
kind: 'message',
instructions: [
...getComputeUnitInstructions({
computeUnitPrice: input.priorityFees,
computeUnitLimit: 'simulated',
}),
getTransferSolInstruction({
source: input.payer,
destination: input.metadata,
amount: input.rent,
}),
getInitializeInstruction({
...input,
programData: input.isCanonical ? input.programData : undefined,
}),
],
};
input: InitializeInput & { payer: TransactionSigner; rent: Lamports }
) {
return sequentialInstructionPlan([
getTransferSolInstruction({
source: input.payer,
destination: input.metadata,
amount: input.rent,
}),
getInitializeInstruction(input),
]);
}

export function getCreateMetadataInstructionPlanUsingBuffer(
input: Omit<MetadataInput, 'rpc' | 'rpcSubscriptions'> &
PdaDetails & { rent: Lamports; chunkSize: number }
): InstructionPlan {
const mainPlan: InstructionPlan = { kind: 'sequential', plans: [] };

mainPlan.plans.push({
kind: 'message',
instructions: [
...getComputeUnitInstructions({
computeUnitPrice: input.priorityFees,
computeUnitLimit: 'simulated',
}),
getTransferSolInstruction({
source: input.payer,
destination: input.metadata,
amount: input.rent,
}),
getAllocateInstruction({
buffer: input.metadata,
authority: input.authority,
program: input.program,
programData: input.isCanonical ? input.programData : undefined,
seed: input.seed,
}),
],
});

if (input.data.length > REALLOC_LIMIT) {
mainPlan.plans.push(
getExtendInstructionPlan({
account: input.metadata,
authority: input.authority,
extraLength: input.data.length,
program: input.program,
programData: input.isCanonical ? input.programData : undefined,
})
);
input: Omit<InitializeInput, 'data'> & {
data: ReadonlyUint8Array;
payer: TransactionSigner;
rent: Lamports;
}

let offset = 0;
const writePlan: InstructionPlan = { kind: 'parallel', plans: [] };
while (offset < input.data.length) {
writePlan.plans.push(
) {
return sequentialInstructionPlan([
getTransferSolInstruction({
source: input.payer,
destination: input.metadata,
amount: input.rent,
}),
getAllocateInstruction({
buffer: input.metadata,
authority: input.authority,
program: input.program,
programData: input.programData,
seed: input.seed,
}),
...(input.data.length > REALLOC_LIMIT
? [
getExtendInstructionPlan({
account: input.metadata,
authority: input.authority,
extraLength: input.data.length,
program: input.program,
programData: input.programData,
}),
]
: []),
parallelInstructionPlan([
getWriteInstructionPlan({
buffer: input.metadata,
authority: input.authority,
offset,
data: input.data.slice(offset, offset + input.chunkSize),
priorityFees: input.priorityFees,
})
);
offset += input.chunkSize;
}
mainPlan.plans.push(writePlan);

mainPlan.plans.push({
kind: 'message',
instructions: [
...getComputeUnitInstructions({
computeUnitPrice: input.priorityFees,
computeUnitLimit: 'simulated',
}),
getInitializeInstruction({
...input,
programData: input.isCanonical ? input.programData : undefined,
system: PROGRAM_METADATA_PROGRAM_ADDRESS,
data: undefined,
data: input.data,
}),
],
});

return mainPlan;
]),
getInitializeInstruction({
...input,
system: PROGRAM_METADATA_PROGRAM_ADDRESS,
data: undefined,
}),
]);
}
1 change: 1 addition & 0 deletions clients/js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './generated';
export * from './instructionPlans';

export * from './createMetadata';
export * from './downloadMetadata';
Expand Down
Loading
Loading