@solana/instruction-plans 0.0.0 → 3.0.0-canary-20250718212840

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +16 -0
  3. package/dist/index.browser.cjs +126 -0
  4. package/dist/index.browser.cjs.map +1 -0
  5. package/dist/index.browser.mjs +118 -0
  6. package/dist/index.browser.mjs.map +1 -0
  7. package/dist/index.native.mjs +118 -0
  8. package/dist/index.native.mjs.map +1 -0
  9. package/dist/index.node.cjs +126 -0
  10. package/dist/index.node.cjs.map +1 -0
  11. package/dist/index.node.mjs +118 -0
  12. package/dist/index.node.mjs.map +1 -0
  13. package/dist/types/index.d.ts +7 -0
  14. package/dist/types/index.d.ts.map +1 -0
  15. package/dist/types/instruction-plan.d.ts +394 -0
  16. package/dist/types/instruction-plan.d.ts.map +1 -0
  17. package/package.json +83 -8
  18. package/.bash_logout +0 -7
  19. package/.bashrc +0 -113
  20. package/.npm/_cacache/content-v2/sha512/0a/b2/1e3ee5df0f0ccadee46eda1eb4c6136ae97aef14c939de8b5587c1eb4184a7c4abcd7fa2e591ce848be56a879a605042c84093030ae19ec85bdbd6263609 +0 -0
  21. package/.npm/_cacache/content-v2/sha512/90/55/fd43ac13e9a04d1e752f2bab216c6e7e51f69ed34d4072903ee65f2a1d2fb3437ad06a02ce93f441e2c91d8acd00e0cfe1d0c3ac6f6f0d0ac143a89b271f +0 -0
  22. package/.npm/_cacache/index-v5/a6/aa/29e44d5a310c9b93c5aa5fba31edf53f53cfa917687cfe0458292b3a2017 +0 -3
  23. package/.npm/_logs/2025-07-17T21_52_29_821Z-debug-0.log +0 -33
  24. package/.npm/_logs/2025-07-17T22_01_15_651Z-debug-0.log +0 -62
  25. package/.npm/_logs/2025-07-17T22_02_14_226Z-debug-0.log +0 -45
  26. package/.npm/_logs/2025-07-17T22_02_53_059Z-debug-0.log +0 -86
  27. package/.npm/_logs/2025-07-17T22_03_31_452Z-debug-0.log +0 -48
  28. package/.npm/_logs/2025-07-17T22_04_15_893Z-debug-0.log +0 -89
  29. package/.npm/_logs/2025-07-17T22_05_07_641Z-debug-0.log +0 -34
  30. package/.npm/_update-notifier-last-checked +0 -0
  31. package/.profile +0 -27
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@solana/errors');
4
+ var transactionMessages = require('@solana/transaction-messages');
5
+ var transactions = require('@solana/transactions');
6
+
7
+ // src/instruction-plan.ts
8
+ function parallelInstructionPlan(plans) {
9
+ return Object.freeze({
10
+ kind: "parallel",
11
+ plans: parseSingleInstructionPlans(plans)
12
+ });
13
+ }
14
+ function sequentialInstructionPlan(plans) {
15
+ return Object.freeze({
16
+ divisible: true,
17
+ kind: "sequential",
18
+ plans: parseSingleInstructionPlans(plans)
19
+ });
20
+ }
21
+ function nonDivisibleSequentialInstructionPlan(plans) {
22
+ return Object.freeze({
23
+ divisible: false,
24
+ kind: "sequential",
25
+ plans: parseSingleInstructionPlans(plans)
26
+ });
27
+ }
28
+ function singleInstructionPlan(instruction) {
29
+ return Object.freeze({ instruction, kind: "single" });
30
+ }
31
+ function parseSingleInstructionPlans(plans) {
32
+ return plans.map((plan) => "kind" in plan ? plan : singleInstructionPlan(plan));
33
+ }
34
+ function getLinearMessagePackerInstructionPlan({
35
+ getInstruction,
36
+ totalLength: totalBytes
37
+ }) {
38
+ return Object.freeze({
39
+ getMessagePacker: () => {
40
+ let offset = 0;
41
+ return Object.freeze({
42
+ done: () => offset >= totalBytes,
43
+ packMessageToCapacity: (message) => {
44
+ if (offset >= totalBytes) {
45
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);
46
+ }
47
+ const messageSizeWithBaseInstruction = transactions.getTransactionMessageSize(
48
+ transactionMessages.appendTransactionMessageInstruction(getInstruction(offset, 0), message)
49
+ );
50
+ const freeSpace = transactions.TRANSACTION_SIZE_LIMIT - messageSizeWithBaseInstruction - 1;
51
+ if (freeSpace <= 0) {
52
+ const messageSize = transactions.getTransactionMessageSize(message);
53
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN, {
54
+ // (+1) We need to pack at least one byte of data otherwise
55
+ // there is no point packing the base instruction alone.
56
+ numBytesRequired: messageSizeWithBaseInstruction - messageSize + 1,
57
+ // (-1) Leeway for shortU16 numbers in transaction headers.
58
+ numFreeBytes: transactions.TRANSACTION_SIZE_LIMIT - messageSize - 1
59
+ });
60
+ }
61
+ const length = Math.min(totalBytes - offset, freeSpace);
62
+ const instruction = getInstruction(offset, length);
63
+ offset += length;
64
+ return transactionMessages.appendTransactionMessageInstruction(instruction, message);
65
+ }
66
+ });
67
+ },
68
+ kind: "messagePacker"
69
+ });
70
+ }
71
+ function getMessagePackerInstructionPlanFromInstructions(instructions) {
72
+ return Object.freeze({
73
+ getMessagePacker: () => {
74
+ let instructionIndex = 0;
75
+ return Object.freeze({
76
+ done: () => instructionIndex >= instructions.length,
77
+ packMessageToCapacity: (message) => {
78
+ if (instructionIndex >= instructions.length) {
79
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);
80
+ }
81
+ const originalMessageSize = transactions.getTransactionMessageSize(message);
82
+ for (let index = instructionIndex; index < instructions.length; index++) {
83
+ message = transactionMessages.appendTransactionMessageInstruction(instructions[index], message);
84
+ const messageSize = transactions.getTransactionMessageSize(message);
85
+ if (messageSize > transactions.TRANSACTION_SIZE_LIMIT) {
86
+ if (index === instructionIndex) {
87
+ throw new errors.SolanaError(
88
+ errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,
89
+ {
90
+ numBytesRequired: messageSize - originalMessageSize,
91
+ numFreeBytes: transactions.TRANSACTION_SIZE_LIMIT - originalMessageSize
92
+ }
93
+ );
94
+ }
95
+ instructionIndex = index;
96
+ return message;
97
+ }
98
+ }
99
+ instructionIndex = instructions.length;
100
+ return message;
101
+ }
102
+ });
103
+ },
104
+ kind: "messagePacker"
105
+ });
106
+ }
107
+ var REALLOC_LIMIT = 10240;
108
+ function getReallocMessagePackerInstructionPlan({
109
+ getInstruction,
110
+ totalSize
111
+ }) {
112
+ const numberOfInstructions = Math.ceil(totalSize / REALLOC_LIMIT);
113
+ const lastInstructionSize = totalSize % REALLOC_LIMIT;
114
+ const instructions = new Array(numberOfInstructions).fill(0).map((_, i) => getInstruction(i === numberOfInstructions - 1 ? lastInstructionSize : REALLOC_LIMIT));
115
+ return getMessagePackerInstructionPlanFromInstructions(instructions);
116
+ }
117
+
118
+ exports.getLinearMessagePackerInstructionPlan = getLinearMessagePackerInstructionPlan;
119
+ exports.getMessagePackerInstructionPlanFromInstructions = getMessagePackerInstructionPlanFromInstructions;
120
+ exports.getReallocMessagePackerInstructionPlan = getReallocMessagePackerInstructionPlan;
121
+ exports.nonDivisibleSequentialInstructionPlan = nonDivisibleSequentialInstructionPlan;
122
+ exports.parallelInstructionPlan = parallelInstructionPlan;
123
+ exports.sequentialInstructionPlan = sequentialInstructionPlan;
124
+ exports.singleInstructionPlan = singleInstructionPlan;
125
+ //# sourceMappingURL=index.node.cjs.map
126
+ //# sourceMappingURL=index.node.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/instruction-plan.ts"],"names":["SolanaError","SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE","getTransactionMessageSize","appendTransactionMessageInstruction","TRANSACTION_SIZE_LIMIT","SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN"],"mappings":"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","file":"index.node.cjs","sourcesContent":["import {\n SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,\n SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE,\n SolanaError,\n} from '@solana/errors';\nimport { Instruction } from '@solana/instructions';\nimport {\n appendTransactionMessageInstruction,\n BaseTransactionMessage,\n TransactionMessageWithFeePayer,\n} from '@solana/transaction-messages';\nimport { getTransactionMessageSize, TRANSACTION_SIZE_LIMIT } from '@solana/transactions';\n\n/**\n * A set of instructions with constraints on how they can be executed.\n *\n * This is structured as a recursive tree of plans in order to allow for\n * parallel execution, sequential execution and combinations of both.\n *\n * Namely the following plans are supported:\n * - {@link SingleInstructionPlan} - A plan that contains a single instruction.\n * This is a simple instruction wrapper and the simplest leaf in this tree.\n * - {@link ParallelInstructionPlan} - A plan that contains other plans that\n * can be executed in parallel.\n * - {@link SequentialInstructionPlan} - A plan that contains other plans that\n * must be executed sequentially. It also defines whether the plan is divisible\n * meaning that instructions inside it can be split into separate transactions.\n * - {@link MessagePackerInstructionPlan} - A plan that can dynamically pack\n * instructions into transaction messages.\n *\n * Helpers are provided for each of these plans to make it easier to create them.\n *\n * @example\n * ```ts\n * const myInstructionPlan: InstructionPlan = parallelInstructionPlan([\n * sequentialInstructionPlan([instructionA, instructionB]),\n * instructionC,\n * instructionD,\n * ]);\n * ```\n *\n * @see {@link SingleInstructionPlan}\n * @see {@link ParallelInstructionPlan}\n * @see {@link SequentialInstructionPlan}\n * @see {@link MessagePackerInstructionPlan}\n */\nexport type InstructionPlan =\n | MessagePackerInstructionPlan\n | ParallelInstructionPlan\n | SequentialInstructionPlan\n | SingleInstructionPlan;\n\n/**\n * A plan wrapping other plans that must be executed sequentially.\n *\n * It also defines whether nested plans are divisible — meaning that\n * the instructions inside them can be split into separate transactions.\n * When `divisible` is `false`, the instructions inside the plan should\n * all be executed atomicly — either in a single transaction or in a\n * transaction bundle.\n *\n * You may use the {@link sequentialInstructionPlan} and {@link nonDivisibleSequentialInstructionPlan}\n * helpers to create objects of this type.\n *\n * @example Simple sequential plan with two instructions.\n * ```ts\n * const plan = sequentialInstructionPlan([instructionA, instructionB]);\n * plan satisfies SequentialInstructionPlan;\n * ```\n *\n * @example Non-divisible sequential plan with two instructions.\n * ```ts\n * const plan = nonDivisibleSequentialInstructionPlan([instructionA, instructionB]);\n * plan satisfies SequentialInstructionPlan & { divisible: false };\n * ```\n *\n * @example Sequential plan with nested parallel plans.\n * Here, instructions A and B can be executed in parallel, but they must both be finalized\n * before instructions C and D can be sent — which can also be executed in parallel.\n * ```ts\n * const plan = sequentialInstructionPlan([\n * parallelInstructionPlan([instructionA, instructionB]),\n * parallelInstructionPlan([instructionC, instructionD]),\n * ]);\n * plan satisfies SequentialInstructionPlan & { divisible: false };\n * ```\n *\n * @see {@link sequentialInstructionPlan}\n * @see {@link nonDivisibleSequentialInstructionPlan}\n */\nexport type SequentialInstructionPlan = Readonly<{\n divisible: boolean;\n kind: 'sequential';\n plans: InstructionPlan[];\n}>;\n\n/**\n * A plan wrapping other plans that can be executed in parallel.\n *\n * This means direct children of this plan can be executed in separate\n * parallel transactions without consequence.\n * However, the children themselves can define additional constraints\n * for that specific branch of the tree — such as the {@link SequentialInstructionPlan}.\n *\n * You may use the {@link parallelInstructionPlan} helper to create objects of this type.\n *\n * @example Simple parallel plan with two instructions.\n * ```ts\n * const plan = parallelInstructionPlan([instructionA, instructionB]);\n * plan satisfies ParallelInstructionPlan;\n * ```\n *\n * @example Parallel plan with nested sequential plans.\n * Here, instructions A and B must be executed sequentially and so must instructions C and D,\n * but both pairs can be executed in parallel.\n * ```ts\n * const plan = parallelInstructionPlan([\n * sequentialInstructionPlan([instructionA, instructionB]),\n * sequentialInstructionPlan([instructionC, instructionD]),\n * ]);\n * plan satisfies ParallelInstructionPlan;\n * ```\n *\n * @see {@link parallelInstructionPlan}\n */\nexport type ParallelInstructionPlan = Readonly<{\n kind: 'parallel';\n plans: InstructionPlan[];\n}>;\n\n/**\n * A plan that contains a single instruction.\n *\n * This is a simple instruction wrapper that transforms an instruction into a plan.\n *\n * You may use the {@link singleInstructionPlan} helper to create objects of this type.\n *\n * @example\n * ```ts\n * const plan = singleInstructionPlan(instructionA);\n * plan satisfies SingleInstructionPlan;\n * ```\n *\n * @see {@link singleInstructionPlan}\n */\nexport type SingleInstructionPlan<TInstruction extends Instruction = Instruction> = Readonly<{\n instruction: TInstruction;\n kind: 'single';\n}>;\n\n/**\n * A plan that can dynamically pack instructions into transaction messages.\n *\n * This plan provides a {@link MessagePacker} via the `getMessagePacker`\n * method, which enables instructions to be dynamically packed into the\n * provided transaction message until there are no more instructions to pack.\n * The returned {@link MessagePacker} offers a `packMessageToCapacity(message)`\n * method that packs the provided message — when possible — and a `done()` method\n * that checks whether there are more instructions to pack.\n *\n * Several helper functions are provided to create objects of this type such as\n * {@link getLinearMessagePackerInstructionPlan} or {@link getMessagePackerInstructionPlanFromInstructions}.\n *\n * @example An message packer plan for a write instruction that uses as many bytes as possible.\n * ```ts\n * const plan = getLinearMessagePackerInstructionPlan({\n * totalLength: dataToWrite.length,\n * getInstruction: (offset, length) =>\n * getWriteInstruction({\n * offset,\n * data: dataToWrite.slice(offset, offset + length),\n * }),\n * });\n * plan satisfies MessagePackerInstructionPlan;\n * ```\n *\n * @example A message packer plan for multiple realloc instructions.\n * ```ts\n * const plan = getReallocMessagePackerInstructionPlan({\n * totalSize: additionalDataSize,\n * getInstruction: (size) => getExtendInstruction({ length: size }),\n * });\n * plan satisfies MessagePackerInstructionPlan;\n * ```\n *\n * @example Using a message packer plan.\n * ```ts\n * let plan: MessagePackerInstructionPlan;\n * const messagePacker = plan.getMessagePacker();\n *\n * while (!messagePacker.done()) {\n * try {\n * transactionMessage = messagePacker.packMessageToCapacity(transactionMessage);\n * } catch (error) {\n * // The current transaction message cannot be used to pack this plan.\n * // We should create a new one and try again.\n * }\n * }\n * ```\n *\n * @see {@link getLinearMessagePackerInstructionPlan}\n * @see {@link getMessagePackerInstructionPlanFromInstructions}\n * @see {@link getReallocMessagePackerInstructionPlan}\n */\nexport type MessagePackerInstructionPlan = Readonly<{\n getMessagePacker: () => MessagePacker;\n kind: 'messagePacker';\n}>;\n\n/**\n * The message packer returned by the {@link MessagePackerInstructionPlan}.\n *\n * It offers a `packMessageToCapacity(transactionMessage)` method that packs as many instructions\n * as possible into the provided transaction message, while still being able to fit into the\n * transaction size limit. It returns the updated transaction message with the packed instructions\n * or throws an error if the current transaction message cannot accommodate this plan.\n *\n * The `done()` method checks whether there are more instructions to pack into\n * transaction messages.\n *\n * @example\n * ```ts\n * let plan: MessagePackerInstructionPlan;\n * const messagePacker = plan.getMessagePacker();\n *\n * while (!messagePacker.done()) {\n * try {\n * transactionMessage = messagePacker.packMessageToCapacity(transactionMessage);\n * } catch (error) {\n * // The current transaction message cannot be used to pack this plan.\n * // We should create a new one and try again.\n * }\n * }\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n */\nexport type MessagePacker = Readonly<{\n /** Checks whether the message packer has more instructions to pack into transaction messages. */\n done: () => boolean;\n /**\n * Packs the provided transaction message with instructions or throws if not possible.\n *\n * @throws {@link SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN}\n * if the provided transaction message cannot be used to fill the next instructions.\n * @throws {@link SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE}\n * if the message packer is already done and no more instructions can be packed.\n */\n packMessageToCapacity: (\n transactionMessage: BaseTransactionMessage & TransactionMessageWithFeePayer,\n ) => BaseTransactionMessage & TransactionMessageWithFeePayer;\n}>;\n\n/**\n * Creates a {@link ParallelInstructionPlan} from an array of nested plans.\n *\n * It can accept {@link Instruction} objects directly, which will be wrapped\n * in {@link SingleInstructionPlan | SingleInstructionPlans} automatically.\n *\n * @example Using explicit {@link SingleInstructionPlan | SingleInstructionPlans}.\n * ```ts\n * const plan = parallelInstructionPlan([\n * singleInstructionPlan(instructionA),\n * singleInstructionPlan(instructionB),\n * ]);\n * ```\n *\n * @example Using {@link Instruction | Instructions} directly.\n * ```ts\n * const plan = parallelInstructionPlan([instructionA, instructionB]);\n * ```\n *\n * @see {@link ParallelInstructionPlan}\n */\nexport function parallelInstructionPlan(plans: (Instruction | InstructionPlan)[]): ParallelInstructionPlan {\n return Object.freeze({\n kind: 'parallel',\n plans: parseSingleInstructionPlans(plans),\n });\n}\n\n/**\n * Creates a divisible {@link SequentialInstructionPlan} from an array of nested plans.\n *\n * It can accept {@link Instruction} objects directly, which will be wrapped\n * in {@link SingleInstructionPlan | SingleInstructionPlans} automatically.\n *\n * @example Using explicit {@link SingleInstructionPlan | SingleInstructionPlans}.\n * ```ts\n * const plan = sequentialInstructionPlan([\n * singleInstructionPlan(instructionA),\n * singleInstructionPlan(instructionB),\n * ]);\n * ```\n *\n * @example Using {@link Instruction | Instructions} directly.\n * ```ts\n * const plan = sequentialInstructionPlan([instructionA, instructionB]);\n * ```\n *\n * @see {@link SequentialInstructionPlan}\n */\nexport function sequentialInstructionPlan(\n plans: (Instruction | InstructionPlan)[],\n): SequentialInstructionPlan & { divisible: true } {\n return Object.freeze({\n divisible: true,\n kind: 'sequential',\n plans: parseSingleInstructionPlans(plans),\n });\n}\n\n/**\n * Creates a non-divisible {@link SequentialInstructionPlan} from an array of nested plans.\n *\n * It can accept {@link Instruction} objects directly, which will be wrapped\n * in {@link SingleInstructionPlan | SingleInstructionPlans} automatically.\n *\n * @example Using explicit {@link SingleInstructionPlan | SingleInstructionPlans}.\n * ```ts\n * const plan = nonDivisibleSequentialInstructionPlan([\n * singleInstructionPlan(instructionA),\n * singleInstructionPlan(instructionB),\n * ]);\n * ```\n *\n * @example Using {@link Instruction | Instructions} directly.\n * ```ts\n * const plan = nonDivisibleSequentialInstructionPlan([instructionA, instructionB]);\n * ```\n *\n * @see {@link SequentialInstructionPlan}\n */\nexport function nonDivisibleSequentialInstructionPlan(\n plans: (Instruction | InstructionPlan)[],\n): SequentialInstructionPlan & { divisible: false } {\n return Object.freeze({\n divisible: false,\n kind: 'sequential',\n plans: parseSingleInstructionPlans(plans),\n });\n}\n\n/**\n * Creates a {@link SingleInstructionPlan} from an {@link Instruction} object.\n *\n * @example\n * ```ts\n * const plan = singleInstructionPlan(instructionA);\n * ```\n *\n * @see {@link SingleInstructionPlan}\n */\nexport function singleInstructionPlan(instruction: Instruction): SingleInstructionPlan {\n return Object.freeze({ instruction, kind: 'single' });\n}\n\nfunction parseSingleInstructionPlans(plans: (Instruction | InstructionPlan)[]): InstructionPlan[] {\n return plans.map(plan => ('kind' in plan ? plan : singleInstructionPlan(plan)));\n}\n\n/**\n * Creates a {@link MessagePackerInstructionPlan} that packs instructions\n * such that each instruction consumes as many bytes as possible from the given\n * `totalLength` while still being able to fit into the given transaction messages.\n *\n * This is particularly useful for instructions that write data to accounts and must\n * span multiple transactions due to their size limit.\n *\n * This message packer will first call `getInstruction` with a length of zero to\n * determine the base size of the instruction before figuring out how many\n * additional bytes can be packed into the transaction message. That remaining space\n * will then be used to call `getInstruction` again with the appropriate length.\n *\n * @param getInstruction - A function that returns an instruction for a given offset and length.\n * @param totalLength - The total length of the data to write, in bytes.\n *\n * @example\n * ```ts\n * const plan = getLinearMessagePackerInstructionPlan({\n * totalLength: dataToWrite.length,\n * getInstruction: (offset, length) =>\n * getWriteInstruction({\n * offset,\n * data: dataToWrite.slice(offset, offset + length),\n * }),\n * });\n * plan satisfies MessagePackerInstructionPlan;\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n */\nexport function getLinearMessagePackerInstructionPlan({\n getInstruction,\n totalLength: totalBytes,\n}: {\n getInstruction: (offset: number, length: number) => Instruction;\n totalLength: number;\n}): MessagePackerInstructionPlan {\n return Object.freeze({\n getMessagePacker: () => {\n let offset = 0;\n return Object.freeze({\n done: () => offset >= totalBytes,\n packMessageToCapacity: (message: BaseTransactionMessage & TransactionMessageWithFeePayer) => {\n if (offset >= totalBytes) {\n throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);\n }\n\n const messageSizeWithBaseInstruction = getTransactionMessageSize(\n appendTransactionMessageInstruction(getInstruction(offset, 0), message),\n );\n const freeSpace =\n TRANSACTION_SIZE_LIMIT -\n messageSizeWithBaseInstruction /* Includes the base instruction (length: 0). */ -\n 1; /* Leeway for shortU16 numbers in transaction headers. */\n\n if (freeSpace <= 0) {\n const messageSize = getTransactionMessageSize(message);\n throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN, {\n // (+1) We need to pack at least one byte of data otherwise\n // there is no point packing the base instruction alone.\n numBytesRequired: messageSizeWithBaseInstruction - messageSize + 1,\n // (-1) Leeway for shortU16 numbers in transaction headers.\n numFreeBytes: TRANSACTION_SIZE_LIMIT - messageSize - 1,\n });\n }\n\n const length = Math.min(totalBytes - offset, freeSpace);\n const instruction = getInstruction(offset, length);\n offset += length;\n return appendTransactionMessageInstruction(instruction, message);\n },\n });\n },\n kind: 'messagePacker',\n });\n}\n\n/**\n * Creates a {@link MessagePackerInstructionPlan} from a list of instructions.\n *\n * This can be useful to prepare a set of instructions that can be iterated over\n * — e.g. to pack a list of instructions that gradually reallocate the size of an account\n * one `REALLOC_LIMIT` (10'240 bytes) at a time.\n *\n * @example\n * ```ts\n * const plan = getMessagePackerInstructionPlanFromInstructions([\n * instructionA,\n * instructionB,\n * instructionC,\n * ]);\n *\n * const messagePacker = plan.getMessagePacker();\n * firstTransactionMessage = messagePacker.packMessageToCapacity(firstTransactionMessage);\n * // Contains instruction A and instruction B.\n * secondTransactionMessage = messagePacker.packMessageToCapacity(secondTransactionMessage);\n * // Contains instruction C.\n * messagePacker.done(); // true\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n * @see {@link getReallocMessagePackerInstructionPlan}\n */\nexport function getMessagePackerInstructionPlanFromInstructions<TInstruction extends Instruction = Instruction>(\n instructions: TInstruction[],\n): MessagePackerInstructionPlan {\n return Object.freeze({\n getMessagePacker: () => {\n let instructionIndex = 0;\n return Object.freeze({\n done: () => instructionIndex >= instructions.length,\n packMessageToCapacity: (message: BaseTransactionMessage & TransactionMessageWithFeePayer) => {\n if (instructionIndex >= instructions.length) {\n throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);\n }\n\n const originalMessageSize = getTransactionMessageSize(message);\n\n for (let index = instructionIndex; index < instructions.length; index++) {\n message = appendTransactionMessageInstruction(instructions[index], message);\n const messageSize = getTransactionMessageSize(message);\n\n if (messageSize > TRANSACTION_SIZE_LIMIT) {\n if (index === instructionIndex) {\n throw new SolanaError(\n SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,\n {\n numBytesRequired: messageSize - originalMessageSize,\n numFreeBytes: TRANSACTION_SIZE_LIMIT - originalMessageSize,\n },\n );\n }\n instructionIndex = index;\n return message;\n }\n }\n\n instructionIndex = instructions.length;\n return message;\n },\n });\n },\n kind: 'messagePacker',\n });\n}\n\nconst REALLOC_LIMIT = 10_240;\n\n/**\n * Creates a {@link MessagePackerInstructionPlan} that packs a list of realloc instructions.\n *\n * That is, it splits instruction by chunks of `REALLOC_LIMIT` (10'240) bytes until\n * the given total size is reached.\n *\n * @example\n * ```ts\n * const plan = getReallocMessagePackerInstructionPlan({\n * totalSize: additionalDataSize,\n * getInstruction: (size) => getExtendInstruction({ length: size }),\n * });\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n */\nexport function getReallocMessagePackerInstructionPlan({\n getInstruction,\n totalSize,\n}: {\n getInstruction: (size: number) => Instruction;\n totalSize: number;\n}): MessagePackerInstructionPlan {\n const numberOfInstructions = Math.ceil(totalSize / REALLOC_LIMIT);\n const lastInstructionSize = totalSize % REALLOC_LIMIT;\n const instructions = new Array(numberOfInstructions)\n .fill(0)\n .map((_, i) => getInstruction(i === numberOfInstructions - 1 ? lastInstructionSize : REALLOC_LIMIT));\n\n return getMessagePackerInstructionPlanFromInstructions(instructions);\n}\n"]}
@@ -0,0 +1,118 @@
1
+ import { SolanaError, SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE, SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN } from '@solana/errors';
2
+ import { appendTransactionMessageInstruction } from '@solana/transaction-messages';
3
+ import { getTransactionMessageSize, TRANSACTION_SIZE_LIMIT } from '@solana/transactions';
4
+
5
+ // src/instruction-plan.ts
6
+ function parallelInstructionPlan(plans) {
7
+ return Object.freeze({
8
+ kind: "parallel",
9
+ plans: parseSingleInstructionPlans(plans)
10
+ });
11
+ }
12
+ function sequentialInstructionPlan(plans) {
13
+ return Object.freeze({
14
+ divisible: true,
15
+ kind: "sequential",
16
+ plans: parseSingleInstructionPlans(plans)
17
+ });
18
+ }
19
+ function nonDivisibleSequentialInstructionPlan(plans) {
20
+ return Object.freeze({
21
+ divisible: false,
22
+ kind: "sequential",
23
+ plans: parseSingleInstructionPlans(plans)
24
+ });
25
+ }
26
+ function singleInstructionPlan(instruction) {
27
+ return Object.freeze({ instruction, kind: "single" });
28
+ }
29
+ function parseSingleInstructionPlans(plans) {
30
+ return plans.map((plan) => "kind" in plan ? plan : singleInstructionPlan(plan));
31
+ }
32
+ function getLinearMessagePackerInstructionPlan({
33
+ getInstruction,
34
+ totalLength: totalBytes
35
+ }) {
36
+ return Object.freeze({
37
+ getMessagePacker: () => {
38
+ let offset = 0;
39
+ return Object.freeze({
40
+ done: () => offset >= totalBytes,
41
+ packMessageToCapacity: (message) => {
42
+ if (offset >= totalBytes) {
43
+ throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);
44
+ }
45
+ const messageSizeWithBaseInstruction = getTransactionMessageSize(
46
+ appendTransactionMessageInstruction(getInstruction(offset, 0), message)
47
+ );
48
+ const freeSpace = TRANSACTION_SIZE_LIMIT - messageSizeWithBaseInstruction - 1;
49
+ if (freeSpace <= 0) {
50
+ const messageSize = getTransactionMessageSize(message);
51
+ throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN, {
52
+ // (+1) We need to pack at least one byte of data otherwise
53
+ // there is no point packing the base instruction alone.
54
+ numBytesRequired: messageSizeWithBaseInstruction - messageSize + 1,
55
+ // (-1) Leeway for shortU16 numbers in transaction headers.
56
+ numFreeBytes: TRANSACTION_SIZE_LIMIT - messageSize - 1
57
+ });
58
+ }
59
+ const length = Math.min(totalBytes - offset, freeSpace);
60
+ const instruction = getInstruction(offset, length);
61
+ offset += length;
62
+ return appendTransactionMessageInstruction(instruction, message);
63
+ }
64
+ });
65
+ },
66
+ kind: "messagePacker"
67
+ });
68
+ }
69
+ function getMessagePackerInstructionPlanFromInstructions(instructions) {
70
+ return Object.freeze({
71
+ getMessagePacker: () => {
72
+ let instructionIndex = 0;
73
+ return Object.freeze({
74
+ done: () => instructionIndex >= instructions.length,
75
+ packMessageToCapacity: (message) => {
76
+ if (instructionIndex >= instructions.length) {
77
+ throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);
78
+ }
79
+ const originalMessageSize = getTransactionMessageSize(message);
80
+ for (let index = instructionIndex; index < instructions.length; index++) {
81
+ message = appendTransactionMessageInstruction(instructions[index], message);
82
+ const messageSize = getTransactionMessageSize(message);
83
+ if (messageSize > TRANSACTION_SIZE_LIMIT) {
84
+ if (index === instructionIndex) {
85
+ throw new SolanaError(
86
+ SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,
87
+ {
88
+ numBytesRequired: messageSize - originalMessageSize,
89
+ numFreeBytes: TRANSACTION_SIZE_LIMIT - originalMessageSize
90
+ }
91
+ );
92
+ }
93
+ instructionIndex = index;
94
+ return message;
95
+ }
96
+ }
97
+ instructionIndex = instructions.length;
98
+ return message;
99
+ }
100
+ });
101
+ },
102
+ kind: "messagePacker"
103
+ });
104
+ }
105
+ var REALLOC_LIMIT = 10240;
106
+ function getReallocMessagePackerInstructionPlan({
107
+ getInstruction,
108
+ totalSize
109
+ }) {
110
+ const numberOfInstructions = Math.ceil(totalSize / REALLOC_LIMIT);
111
+ const lastInstructionSize = totalSize % REALLOC_LIMIT;
112
+ const instructions = new Array(numberOfInstructions).fill(0).map((_, i) => getInstruction(i === numberOfInstructions - 1 ? lastInstructionSize : REALLOC_LIMIT));
113
+ return getMessagePackerInstructionPlanFromInstructions(instructions);
114
+ }
115
+
116
+ export { getLinearMessagePackerInstructionPlan, getMessagePackerInstructionPlanFromInstructions, getReallocMessagePackerInstructionPlan, nonDivisibleSequentialInstructionPlan, parallelInstructionPlan, sequentialInstructionPlan, singleInstructionPlan };
117
+ //# sourceMappingURL=index.node.mjs.map
118
+ //# sourceMappingURL=index.node.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/instruction-plan.ts"],"names":[],"mappings":"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","file":"index.node.mjs","sourcesContent":["import {\n SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,\n SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE,\n SolanaError,\n} from '@solana/errors';\nimport { Instruction } from '@solana/instructions';\nimport {\n appendTransactionMessageInstruction,\n BaseTransactionMessage,\n TransactionMessageWithFeePayer,\n} from '@solana/transaction-messages';\nimport { getTransactionMessageSize, TRANSACTION_SIZE_LIMIT } from '@solana/transactions';\n\n/**\n * A set of instructions with constraints on how they can be executed.\n *\n * This is structured as a recursive tree of plans in order to allow for\n * parallel execution, sequential execution and combinations of both.\n *\n * Namely the following plans are supported:\n * - {@link SingleInstructionPlan} - A plan that contains a single instruction.\n * This is a simple instruction wrapper and the simplest leaf in this tree.\n * - {@link ParallelInstructionPlan} - A plan that contains other plans that\n * can be executed in parallel.\n * - {@link SequentialInstructionPlan} - A plan that contains other plans that\n * must be executed sequentially. It also defines whether the plan is divisible\n * meaning that instructions inside it can be split into separate transactions.\n * - {@link MessagePackerInstructionPlan} - A plan that can dynamically pack\n * instructions into transaction messages.\n *\n * Helpers are provided for each of these plans to make it easier to create them.\n *\n * @example\n * ```ts\n * const myInstructionPlan: InstructionPlan = parallelInstructionPlan([\n * sequentialInstructionPlan([instructionA, instructionB]),\n * instructionC,\n * instructionD,\n * ]);\n * ```\n *\n * @see {@link SingleInstructionPlan}\n * @see {@link ParallelInstructionPlan}\n * @see {@link SequentialInstructionPlan}\n * @see {@link MessagePackerInstructionPlan}\n */\nexport type InstructionPlan =\n | MessagePackerInstructionPlan\n | ParallelInstructionPlan\n | SequentialInstructionPlan\n | SingleInstructionPlan;\n\n/**\n * A plan wrapping other plans that must be executed sequentially.\n *\n * It also defines whether nested plans are divisible — meaning that\n * the instructions inside them can be split into separate transactions.\n * When `divisible` is `false`, the instructions inside the plan should\n * all be executed atomicly — either in a single transaction or in a\n * transaction bundle.\n *\n * You may use the {@link sequentialInstructionPlan} and {@link nonDivisibleSequentialInstructionPlan}\n * helpers to create objects of this type.\n *\n * @example Simple sequential plan with two instructions.\n * ```ts\n * const plan = sequentialInstructionPlan([instructionA, instructionB]);\n * plan satisfies SequentialInstructionPlan;\n * ```\n *\n * @example Non-divisible sequential plan with two instructions.\n * ```ts\n * const plan = nonDivisibleSequentialInstructionPlan([instructionA, instructionB]);\n * plan satisfies SequentialInstructionPlan & { divisible: false };\n * ```\n *\n * @example Sequential plan with nested parallel plans.\n * Here, instructions A and B can be executed in parallel, but they must both be finalized\n * before instructions C and D can be sent — which can also be executed in parallel.\n * ```ts\n * const plan = sequentialInstructionPlan([\n * parallelInstructionPlan([instructionA, instructionB]),\n * parallelInstructionPlan([instructionC, instructionD]),\n * ]);\n * plan satisfies SequentialInstructionPlan & { divisible: false };\n * ```\n *\n * @see {@link sequentialInstructionPlan}\n * @see {@link nonDivisibleSequentialInstructionPlan}\n */\nexport type SequentialInstructionPlan = Readonly<{\n divisible: boolean;\n kind: 'sequential';\n plans: InstructionPlan[];\n}>;\n\n/**\n * A plan wrapping other plans that can be executed in parallel.\n *\n * This means direct children of this plan can be executed in separate\n * parallel transactions without consequence.\n * However, the children themselves can define additional constraints\n * for that specific branch of the tree — such as the {@link SequentialInstructionPlan}.\n *\n * You may use the {@link parallelInstructionPlan} helper to create objects of this type.\n *\n * @example Simple parallel plan with two instructions.\n * ```ts\n * const plan = parallelInstructionPlan([instructionA, instructionB]);\n * plan satisfies ParallelInstructionPlan;\n * ```\n *\n * @example Parallel plan with nested sequential plans.\n * Here, instructions A and B must be executed sequentially and so must instructions C and D,\n * but both pairs can be executed in parallel.\n * ```ts\n * const plan = parallelInstructionPlan([\n * sequentialInstructionPlan([instructionA, instructionB]),\n * sequentialInstructionPlan([instructionC, instructionD]),\n * ]);\n * plan satisfies ParallelInstructionPlan;\n * ```\n *\n * @see {@link parallelInstructionPlan}\n */\nexport type ParallelInstructionPlan = Readonly<{\n kind: 'parallel';\n plans: InstructionPlan[];\n}>;\n\n/**\n * A plan that contains a single instruction.\n *\n * This is a simple instruction wrapper that transforms an instruction into a plan.\n *\n * You may use the {@link singleInstructionPlan} helper to create objects of this type.\n *\n * @example\n * ```ts\n * const plan = singleInstructionPlan(instructionA);\n * plan satisfies SingleInstructionPlan;\n * ```\n *\n * @see {@link singleInstructionPlan}\n */\nexport type SingleInstructionPlan<TInstruction extends Instruction = Instruction> = Readonly<{\n instruction: TInstruction;\n kind: 'single';\n}>;\n\n/**\n * A plan that can dynamically pack instructions into transaction messages.\n *\n * This plan provides a {@link MessagePacker} via the `getMessagePacker`\n * method, which enables instructions to be dynamically packed into the\n * provided transaction message until there are no more instructions to pack.\n * The returned {@link MessagePacker} offers a `packMessageToCapacity(message)`\n * method that packs the provided message — when possible — and a `done()` method\n * that checks whether there are more instructions to pack.\n *\n * Several helper functions are provided to create objects of this type such as\n * {@link getLinearMessagePackerInstructionPlan} or {@link getMessagePackerInstructionPlanFromInstructions}.\n *\n * @example An message packer plan for a write instruction that uses as many bytes as possible.\n * ```ts\n * const plan = getLinearMessagePackerInstructionPlan({\n * totalLength: dataToWrite.length,\n * getInstruction: (offset, length) =>\n * getWriteInstruction({\n * offset,\n * data: dataToWrite.slice(offset, offset + length),\n * }),\n * });\n * plan satisfies MessagePackerInstructionPlan;\n * ```\n *\n * @example A message packer plan for multiple realloc instructions.\n * ```ts\n * const plan = getReallocMessagePackerInstructionPlan({\n * totalSize: additionalDataSize,\n * getInstruction: (size) => getExtendInstruction({ length: size }),\n * });\n * plan satisfies MessagePackerInstructionPlan;\n * ```\n *\n * @example Using a message packer plan.\n * ```ts\n * let plan: MessagePackerInstructionPlan;\n * const messagePacker = plan.getMessagePacker();\n *\n * while (!messagePacker.done()) {\n * try {\n * transactionMessage = messagePacker.packMessageToCapacity(transactionMessage);\n * } catch (error) {\n * // The current transaction message cannot be used to pack this plan.\n * // We should create a new one and try again.\n * }\n * }\n * ```\n *\n * @see {@link getLinearMessagePackerInstructionPlan}\n * @see {@link getMessagePackerInstructionPlanFromInstructions}\n * @see {@link getReallocMessagePackerInstructionPlan}\n */\nexport type MessagePackerInstructionPlan = Readonly<{\n getMessagePacker: () => MessagePacker;\n kind: 'messagePacker';\n}>;\n\n/**\n * The message packer returned by the {@link MessagePackerInstructionPlan}.\n *\n * It offers a `packMessageToCapacity(transactionMessage)` method that packs as many instructions\n * as possible into the provided transaction message, while still being able to fit into the\n * transaction size limit. It returns the updated transaction message with the packed instructions\n * or throws an error if the current transaction message cannot accommodate this plan.\n *\n * The `done()` method checks whether there are more instructions to pack into\n * transaction messages.\n *\n * @example\n * ```ts\n * let plan: MessagePackerInstructionPlan;\n * const messagePacker = plan.getMessagePacker();\n *\n * while (!messagePacker.done()) {\n * try {\n * transactionMessage = messagePacker.packMessageToCapacity(transactionMessage);\n * } catch (error) {\n * // The current transaction message cannot be used to pack this plan.\n * // We should create a new one and try again.\n * }\n * }\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n */\nexport type MessagePacker = Readonly<{\n /** Checks whether the message packer has more instructions to pack into transaction messages. */\n done: () => boolean;\n /**\n * Packs the provided transaction message with instructions or throws if not possible.\n *\n * @throws {@link SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN}\n * if the provided transaction message cannot be used to fill the next instructions.\n * @throws {@link SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE}\n * if the message packer is already done and no more instructions can be packed.\n */\n packMessageToCapacity: (\n transactionMessage: BaseTransactionMessage & TransactionMessageWithFeePayer,\n ) => BaseTransactionMessage & TransactionMessageWithFeePayer;\n}>;\n\n/**\n * Creates a {@link ParallelInstructionPlan} from an array of nested plans.\n *\n * It can accept {@link Instruction} objects directly, which will be wrapped\n * in {@link SingleInstructionPlan | SingleInstructionPlans} automatically.\n *\n * @example Using explicit {@link SingleInstructionPlan | SingleInstructionPlans}.\n * ```ts\n * const plan = parallelInstructionPlan([\n * singleInstructionPlan(instructionA),\n * singleInstructionPlan(instructionB),\n * ]);\n * ```\n *\n * @example Using {@link Instruction | Instructions} directly.\n * ```ts\n * const plan = parallelInstructionPlan([instructionA, instructionB]);\n * ```\n *\n * @see {@link ParallelInstructionPlan}\n */\nexport function parallelInstructionPlan(plans: (Instruction | InstructionPlan)[]): ParallelInstructionPlan {\n return Object.freeze({\n kind: 'parallel',\n plans: parseSingleInstructionPlans(plans),\n });\n}\n\n/**\n * Creates a divisible {@link SequentialInstructionPlan} from an array of nested plans.\n *\n * It can accept {@link Instruction} objects directly, which will be wrapped\n * in {@link SingleInstructionPlan | SingleInstructionPlans} automatically.\n *\n * @example Using explicit {@link SingleInstructionPlan | SingleInstructionPlans}.\n * ```ts\n * const plan = sequentialInstructionPlan([\n * singleInstructionPlan(instructionA),\n * singleInstructionPlan(instructionB),\n * ]);\n * ```\n *\n * @example Using {@link Instruction | Instructions} directly.\n * ```ts\n * const plan = sequentialInstructionPlan([instructionA, instructionB]);\n * ```\n *\n * @see {@link SequentialInstructionPlan}\n */\nexport function sequentialInstructionPlan(\n plans: (Instruction | InstructionPlan)[],\n): SequentialInstructionPlan & { divisible: true } {\n return Object.freeze({\n divisible: true,\n kind: 'sequential',\n plans: parseSingleInstructionPlans(plans),\n });\n}\n\n/**\n * Creates a non-divisible {@link SequentialInstructionPlan} from an array of nested plans.\n *\n * It can accept {@link Instruction} objects directly, which will be wrapped\n * in {@link SingleInstructionPlan | SingleInstructionPlans} automatically.\n *\n * @example Using explicit {@link SingleInstructionPlan | SingleInstructionPlans}.\n * ```ts\n * const plan = nonDivisibleSequentialInstructionPlan([\n * singleInstructionPlan(instructionA),\n * singleInstructionPlan(instructionB),\n * ]);\n * ```\n *\n * @example Using {@link Instruction | Instructions} directly.\n * ```ts\n * const plan = nonDivisibleSequentialInstructionPlan([instructionA, instructionB]);\n * ```\n *\n * @see {@link SequentialInstructionPlan}\n */\nexport function nonDivisibleSequentialInstructionPlan(\n plans: (Instruction | InstructionPlan)[],\n): SequentialInstructionPlan & { divisible: false } {\n return Object.freeze({\n divisible: false,\n kind: 'sequential',\n plans: parseSingleInstructionPlans(plans),\n });\n}\n\n/**\n * Creates a {@link SingleInstructionPlan} from an {@link Instruction} object.\n *\n * @example\n * ```ts\n * const plan = singleInstructionPlan(instructionA);\n * ```\n *\n * @see {@link SingleInstructionPlan}\n */\nexport function singleInstructionPlan(instruction: Instruction): SingleInstructionPlan {\n return Object.freeze({ instruction, kind: 'single' });\n}\n\nfunction parseSingleInstructionPlans(plans: (Instruction | InstructionPlan)[]): InstructionPlan[] {\n return plans.map(plan => ('kind' in plan ? plan : singleInstructionPlan(plan)));\n}\n\n/**\n * Creates a {@link MessagePackerInstructionPlan} that packs instructions\n * such that each instruction consumes as many bytes as possible from the given\n * `totalLength` while still being able to fit into the given transaction messages.\n *\n * This is particularly useful for instructions that write data to accounts and must\n * span multiple transactions due to their size limit.\n *\n * This message packer will first call `getInstruction` with a length of zero to\n * determine the base size of the instruction before figuring out how many\n * additional bytes can be packed into the transaction message. That remaining space\n * will then be used to call `getInstruction` again with the appropriate length.\n *\n * @param getInstruction - A function that returns an instruction for a given offset and length.\n * @param totalLength - The total length of the data to write, in bytes.\n *\n * @example\n * ```ts\n * const plan = getLinearMessagePackerInstructionPlan({\n * totalLength: dataToWrite.length,\n * getInstruction: (offset, length) =>\n * getWriteInstruction({\n * offset,\n * data: dataToWrite.slice(offset, offset + length),\n * }),\n * });\n * plan satisfies MessagePackerInstructionPlan;\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n */\nexport function getLinearMessagePackerInstructionPlan({\n getInstruction,\n totalLength: totalBytes,\n}: {\n getInstruction: (offset: number, length: number) => Instruction;\n totalLength: number;\n}): MessagePackerInstructionPlan {\n return Object.freeze({\n getMessagePacker: () => {\n let offset = 0;\n return Object.freeze({\n done: () => offset >= totalBytes,\n packMessageToCapacity: (message: BaseTransactionMessage & TransactionMessageWithFeePayer) => {\n if (offset >= totalBytes) {\n throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);\n }\n\n const messageSizeWithBaseInstruction = getTransactionMessageSize(\n appendTransactionMessageInstruction(getInstruction(offset, 0), message),\n );\n const freeSpace =\n TRANSACTION_SIZE_LIMIT -\n messageSizeWithBaseInstruction /* Includes the base instruction (length: 0). */ -\n 1; /* Leeway for shortU16 numbers in transaction headers. */\n\n if (freeSpace <= 0) {\n const messageSize = getTransactionMessageSize(message);\n throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN, {\n // (+1) We need to pack at least one byte of data otherwise\n // there is no point packing the base instruction alone.\n numBytesRequired: messageSizeWithBaseInstruction - messageSize + 1,\n // (-1) Leeway for shortU16 numbers in transaction headers.\n numFreeBytes: TRANSACTION_SIZE_LIMIT - messageSize - 1,\n });\n }\n\n const length = Math.min(totalBytes - offset, freeSpace);\n const instruction = getInstruction(offset, length);\n offset += length;\n return appendTransactionMessageInstruction(instruction, message);\n },\n });\n },\n kind: 'messagePacker',\n });\n}\n\n/**\n * Creates a {@link MessagePackerInstructionPlan} from a list of instructions.\n *\n * This can be useful to prepare a set of instructions that can be iterated over\n * — e.g. to pack a list of instructions that gradually reallocate the size of an account\n * one `REALLOC_LIMIT` (10'240 bytes) at a time.\n *\n * @example\n * ```ts\n * const plan = getMessagePackerInstructionPlanFromInstructions([\n * instructionA,\n * instructionB,\n * instructionC,\n * ]);\n *\n * const messagePacker = plan.getMessagePacker();\n * firstTransactionMessage = messagePacker.packMessageToCapacity(firstTransactionMessage);\n * // Contains instruction A and instruction B.\n * secondTransactionMessage = messagePacker.packMessageToCapacity(secondTransactionMessage);\n * // Contains instruction C.\n * messagePacker.done(); // true\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n * @see {@link getReallocMessagePackerInstructionPlan}\n */\nexport function getMessagePackerInstructionPlanFromInstructions<TInstruction extends Instruction = Instruction>(\n instructions: TInstruction[],\n): MessagePackerInstructionPlan {\n return Object.freeze({\n getMessagePacker: () => {\n let instructionIndex = 0;\n return Object.freeze({\n done: () => instructionIndex >= instructions.length,\n packMessageToCapacity: (message: BaseTransactionMessage & TransactionMessageWithFeePayer) => {\n if (instructionIndex >= instructions.length) {\n throw new SolanaError(SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE);\n }\n\n const originalMessageSize = getTransactionMessageSize(message);\n\n for (let index = instructionIndex; index < instructions.length; index++) {\n message = appendTransactionMessageInstruction(instructions[index], message);\n const messageSize = getTransactionMessageSize(message);\n\n if (messageSize > TRANSACTION_SIZE_LIMIT) {\n if (index === instructionIndex) {\n throw new SolanaError(\n SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,\n {\n numBytesRequired: messageSize - originalMessageSize,\n numFreeBytes: TRANSACTION_SIZE_LIMIT - originalMessageSize,\n },\n );\n }\n instructionIndex = index;\n return message;\n }\n }\n\n instructionIndex = instructions.length;\n return message;\n },\n });\n },\n kind: 'messagePacker',\n });\n}\n\nconst REALLOC_LIMIT = 10_240;\n\n/**\n * Creates a {@link MessagePackerInstructionPlan} that packs a list of realloc instructions.\n *\n * That is, it splits instruction by chunks of `REALLOC_LIMIT` (10'240) bytes until\n * the given total size is reached.\n *\n * @example\n * ```ts\n * const plan = getReallocMessagePackerInstructionPlan({\n * totalSize: additionalDataSize,\n * getInstruction: (size) => getExtendInstruction({ length: size }),\n * });\n * ```\n *\n * @see {@link MessagePackerInstructionPlan}\n */\nexport function getReallocMessagePackerInstructionPlan({\n getInstruction,\n totalSize,\n}: {\n getInstruction: (size: number) => Instruction;\n totalSize: number;\n}): MessagePackerInstructionPlan {\n const numberOfInstructions = Math.ceil(totalSize / REALLOC_LIMIT);\n const lastInstructionSize = totalSize % REALLOC_LIMIT;\n const instructions = new Array(numberOfInstructions)\n .fill(0)\n .map((_, i) => getInstruction(i === numberOfInstructions - 1 ? lastInstructionSize : REALLOC_LIMIT));\n\n return getMessagePackerInstructionPlanFromInstructions(instructions);\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * TODO
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export * from './instruction-plan';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,oBAAoB,CAAC"}