Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 39 additions & 0 deletions .changeset/dry-trees-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
'@solana/instruction-plans': major
---

The `executeTransactionMessage` callback in `createTransactionPlanExecutor` now receives a mutable context object as its first argument. This context can be incrementally populated during execution (e.g. with the latest transaction message, the compiled transaction, or custom properties) and is preserved in the resulting `SingleTransactionPlanResult` regardless of the outcome. If an error is thrown at any point in the callback, any attributes already saved to the context will still be available in the `FailedSingleTransactionPlanResult`, which is useful for debugging failures or building recovery plans.

The callback must now return either a `Signature` or a full `Transaction` object directly, instead of wrapping the result in an object.

**BREAKING CHANGES**

**`executeTransactionMessage` callback signature changed.** The callback now receives `(context, message, config)` instead of `(message, config)` and returns `Signature | Transaction` instead of `{ transaction: Transaction } | { signature: Signature }`.

```diff
const executor = createTransactionPlanExecutor({
- executeTransactionMessage: async (message, { abortSignal }) => {
+ executeTransactionMessage: async (context, message, { abortSignal }) => {
const transaction = await signTransactionMessageWithSigners(message);
+ context.transaction = transaction;
await sendAndConfirmTransaction(transaction, { commitment: 'confirmed' });
- return { transaction };
+ return transaction;
}
});
```

**Custom context is now set via mutation instead of being returned.** Previously, custom context was returned as part of the result object. Now, it must be set directly on the mutable context argument.

```diff
const executor = createTransactionPlanExecutor({
- executeTransactionMessage: async (message) => {
- const transaction = await signAndSend(message);
- return { transaction, context: { custom: 'value' } };
+ executeTransactionMessage: async (context, message) => {
+ context.custom = 'value';
+ const transaction = await signAndSend(message);
+ return transaction;
}
});
```
11 changes: 9 additions & 2 deletions examples/token-airdrop/src/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ const transactionExecutor = createTransactionPlanExecutor({
* It is responsible for signing, sending, and confirming the transaction message.
* It only needs to deal with one transaction message.
*/
async executeTransactionMessage(message, config) {
async executeTransactionMessage(context, message, config) {
const abortSignal = config ? config.abortSignal : undefined;

/**
Expand All @@ -197,20 +197,27 @@ const transactionExecutor = createTransactionPlanExecutor({
tx => estimateAndSetCULimit(tx, { abortSignal }),
);

// Store the updated message in the context for potential error handling.
context.message = updatedMessage;

// Sign this updated transaction message with any signers included in its instructions
const signedTransaction = await signTransactionMessageWithSigners(updatedMessage, { abortSignal });

const signature = getSignatureFromTransaction(signedTransaction);
log.info({ signature }, `[transaction executor] Sending transaction`);

// Store the signed transaction and its signature in the context for potential error handling.
context.transaction = signedTransaction;
context.signature = signature;

// Send and confirm the transaction using the helper we created earlier
assertIsTransactionWithBlockhashLifetime(signedTransaction);
await sendAndConfirmTransaction(signedTransaction, { abortSignal, commitment: 'confirmed' });
log.info(
{ signature },
`[transaction executor] Transaction confirmed: https://explorer.solana.com/tx/${signature}?cluster=custom&customUrl=127.0.0.1:8899`,
);
return { transaction: signedTransaction };
return signedTransaction;
},
});

Expand Down
Loading
Loading