Skip to content

Commit

Permalink
Update useTransactionProcessor.ts
Browse files Browse the repository at this point in the history
implement legacy/versioned tx handling
  • Loading branch information
amilz committed Jul 1, 2024
1 parent a149955 commit cd612ec
Showing 1 changed file with 43 additions and 29 deletions.
72 changes: 43 additions & 29 deletions sample-dapps/solana-action-blinker/hooks/useTransactionProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { Transaction, VersionedMessage, VersionedTransaction } from "@solana/web3.js";
import { useState, useEffect, useCallback } from 'react';
import { Transaction, VersionedTransaction } from "@solana/web3.js";
import { useWallet } from "@solana/wallet-adapter-react";
import { getExplorerUrl } from "@/utils/solana";
import { ActionPostResponse } from '@solana/actions';
Expand All @@ -11,7 +11,7 @@ const useTransactionProcessor = (postResults?: ActionPostResponse | null) => {
const [transactionUrl, setTransactionUrl] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);

const sendAndConfirm = async (serializedTx: string) => {
const sendAndConfirm = useCallback(async (serializedTx: string): Promise<string> => {
if (!serializedTx) throw new Error('No transaction to send');
const API_ENDPOINT = '/api/solana/sendAndConfirm';

Expand All @@ -20,45 +20,59 @@ const useTransactionProcessor = (postResults?: ActionPostResponse | null) => {
try {
const response = await fetch(API_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ serializedTx }),
});
if (response.ok) {
const data = await response.json();
return data.signature;
} else {
setTransactionError('Failed to send and confirm Tx');
if (!response.ok) {
throw new Error('Failed to send and confirm Tx');
}
const data = await response.json();
return data.signature;
} catch (error) {
setTransactionError('Failed to send and confirm Tx');
throw new Error('Failed to send and confirm Tx');
throw error;
} finally {
setIsLoading(false);
}
}
}, []);

const processLegacyTransaction = useCallback(async (transaction: string): Promise<string> => {
if (!signTransaction) throw new Error('Wallet not connected');

const txPartial = Transaction.from(Buffer.from(transaction, 'base64'));
const txSigned = await signTransaction(txPartial);
const txFullSerialized = txSigned.serialize({ requireAllSignatures: true });
const txFullBase64 = txFullSerialized.toString('base64');
return await sendAndConfirm(txFullBase64);
}, [signTransaction, sendAndConfirm]);

const processVersionedTransaction = useCallback(async (transaction: string): Promise<string> => {
if (!signTransaction) throw new Error('Wallet not connected');

const base64Encoder = getBase64Encoder();
const transactionUint8Array = new Uint8Array(base64Encoder.encode(transaction));
const transactionV2 = VersionedTransaction.deserialize(transactionUint8Array);
const txSigned = await signTransaction(transactionV2);
const txFullSerialized = txSigned.serialize();
const txFullBase64 = Buffer.from(txFullSerialized).toString('base64');
return await sendAndConfirm(txFullBase64);
}, [signTransaction, sendAndConfirm]);

useEffect(() => {
const processTransaction = async () => {
if (!postResults || !signTransaction) return;
if (!postResults?.transaction || !signTransaction) return;

try {
const { transaction } = postResults;
if (!transaction) {
throw new Error("Failed to generate transaction");
let signature: string;
try {
signature = await processLegacyTransaction(postResults.transaction);
} catch (err) {
if (err instanceof Error && err.message.includes('VersionedMessage.deserialize()')) {
signature = await processVersionedTransaction(postResults.transaction);
} else {
throw err;
}
}

// Thanks @Callum
// https://solana.stackexchange.com/questions/9775/how-to-deserialize-a-magic-links-versioned-transaction
const base64Encoder = getBase64Encoder();
const readonlyTransactionUint8Array = base64Encoder.encode(transaction);
const transactionUint8Array = new Uint8Array(readonlyTransactionUint8Array);
const transactionV2 = VersionedTransaction.deserialize(transactionUint8Array);
const txSigned = await signTransaction(transactionV2);
const txFullSerialized = txSigned.serialize();
const txFullBase64 = txFullSerialized.toString();
const signature = await sendAndConfirm(txFullBase64);
const explorerUrl = getExplorerUrl(signature);
setTransactionUrl(explorerUrl);
} catch (err) {
Expand All @@ -68,7 +82,7 @@ const useTransactionProcessor = (postResults?: ActionPostResponse | null) => {
};

processTransaction();
}, [postResults, signTransaction]);
}, [postResults, signTransaction, processLegacyTransaction, processVersionedTransaction]);

return { transactionError, transactionUrl, isLoading };
};
Expand Down

0 comments on commit cd612ec

Please sign in to comment.