diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx
index 79d57bf..3a22355 100644
--- a/app/(app)/layout.tsx
+++ b/app/(app)/layout.tsx
@@ -121,6 +121,8 @@ const AppLayout = async ({ children }: { children: React.ReactNode }) => {
,
success: ,
diff --git a/components/CreateTransactionButton.tsx b/components/CreateTransactionButton.tsx
index 2991a03..e5649b1 100644
--- a/components/CreateTransactionButton.tsx
+++ b/components/CreateTransactionButton.tsx
@@ -14,9 +14,9 @@ import * as multisig from "@sqds/multisig";
import { useWallet } from "@solana/wallet-adapter-react";
import {
Connection,
+ Message,
PublicKey,
TransactionInstruction,
- TransactionMessage,
clusterApiUrl,
} from "@solana/web3.js";
import { Input } from "./ui/input";
@@ -54,7 +54,7 @@ const CreateTransaction = ({
programId: programId ? new PublicKey(programId) : multisig.PROGRAM_ID,
})[0];
- const dummyMessage = new TransactionMessage({
+ const dummyMessage = Message.compile({
instructions: [
new TransactionInstruction({
keys: [
@@ -72,7 +72,7 @@ const CreateTransaction = ({
],
payerKey: vaultAddress,
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
- }).compileToLegacyMessage();
+ });
const encoded = bs58.default.encode(dummyMessage.serialize());
@@ -100,17 +100,22 @@ const CreateTransaction = ({
/>
diff --git a/lib/transaction/decodeAndDeserialize.ts b/lib/transaction/decodeAndDeserialize.ts
index 31cd53d..c31b13b 100644
--- a/lib/transaction/decodeAndDeserialize.ts
+++ b/lib/transaction/decodeAndDeserialize.ts
@@ -1,18 +1,66 @@
import * as bs58 from "bs58";
-import { VersionedMessage } from "@solana/web3.js";
+import {
+ Message,
+ MessageAccountKeys,
+ MessageV0,
+ PublicKey,
+ Transaction,
+ TransactionMessage,
+ VersionedMessage,
+ VersionedTransaction,
+} from "@solana/web3.js";
-export function decodeAndDeserialize(tx: string): {
- message: VersionedMessage;
+interface DeserializedTransaction {
+ message: TransactionMessage;
version: number | "legacy";
-} {
+ accountKeys: PublicKey[];
+}
+
+/**
+ * Decodes a base58 encoded transaction and deserializes it into a TransactionMessage
+ * @param tx - Base58 encoded transaction string
+ * @returns Object containing the deserialized message, version, and account keys
+ * @throws Error if deserialization fails
+ */
+export function decodeAndDeserialize(tx: string): DeserializedTransaction {
+ if (!tx) {
+ throw new Error("Transaction string is required");
+ }
+
try {
const messageBytes = bs58.default.decode(tx);
const version = VersionedMessage.deserializeMessageVersion(messageBytes);
- const message = VersionedMessage.deserialize(messageBytes);
+ let message: TransactionMessage;
+ let accountKeys: PublicKey[];
+
+ if (version === "legacy") {
+ const legacyMessage = Message.from(messageBytes);
+ accountKeys = legacyMessage.accountKeys;
+
+ const intermediate = VersionedMessage.deserialize(
+ new MessageV0(legacyMessage).serialize()
+ );
+ message = TransactionMessage.decompile(intermediate, {
+ addressLookupTableAccounts: [],
+ });
+ } else {
+ const versionedMessage = VersionedMessage.deserialize(messageBytes);
+ accountKeys = versionedMessage.staticAccountKeys;
+
+ message = TransactionMessage.decompile(versionedMessage, {
+ addressLookupTableAccounts: [],
+ });
+ }
- return { version, message };
+ return {
+ version,
+ message,
+ accountKeys,
+ };
} catch (error) {
- console.error(error);
- throw new Error("Failed to decode transaction.");
+ if (error instanceof Error) {
+ throw new Error(`Failed to decode transaction: ${error.message}`);
+ }
+ throw new Error("Failed to decode transaction: Unknown error");
}
}
diff --git a/lib/transaction/getAccountsForSimulation.ts b/lib/transaction/getAccountsForSimulation.ts
index 4d7270b..767d1af 100644
--- a/lib/transaction/getAccountsForSimulation.ts
+++ b/lib/transaction/getAccountsForSimulation.ts
@@ -26,7 +26,12 @@ export async function getAccountsForSimulation(
const { staticAccountKeys, accountKeysFromLookups } =
tx.message.getAccountKeys({ addressLookupTableAccounts });
- const staticAddresses = staticAccountKeys.map((k) => k.toString());
+ const staticAddresses = staticAccountKeys.reduce((acc, k) => {
+ if (!k.equals(SystemProgram.programId)) {
+ acc.push(k.toString());
+ }
+ return acc;
+ }, [] as string[]);
const addressesFromLookups = accountKeysFromLookups
? accountKeysFromLookups.writable.map((k) => k.toString())
diff --git a/lib/transaction/importTransaction.ts b/lib/transaction/importTransaction.ts
index 9eaa0ad..4a34356 100644
--- a/lib/transaction/importTransaction.ts
+++ b/lib/transaction/importTransaction.ts
@@ -3,6 +3,7 @@ import {
Connection,
PublicKey,
TransactionMessage,
+ VersionedMessage,
VersionedTransaction,
} from "@solana/web3.js";
import { decodeAndDeserialize } from "./decodeAndDeserialize";
@@ -29,7 +30,7 @@ export const importTransaction = async (
new PublicKey(multisigPda)
);
- const transactionMessage = TransactionMessage.decompile(message);
+ const transactionMessage = new TransactionMessage(message);
const addressLookupTableAccounts =
version === 0
diff --git a/lib/transaction/simulateEncodedTransaction.ts b/lib/transaction/simulateEncodedTransaction.ts
index 195fdb6..267ec3d 100644
--- a/lib/transaction/simulateEncodedTransaction.ts
+++ b/lib/transaction/simulateEncodedTransaction.ts
@@ -15,12 +15,12 @@ export const simulateEncodedTransaction = async (
try {
const { message, version } = decodeAndDeserialize(tx);
- const transaction = new VersionedTransaction(message);
+ const transaction = new VersionedTransaction(message.compileToV0Message());
const keys = await getAccountsForSimulation(
connection,
transaction,
- version === "legacy"
+ version === 0
);
toast.loading("Simulating...", {