Skip to content

Commit 70c782d

Browse files
committed
fix: sell flow uses manual instructions (Phantom blocks signTransaction)
Phantom flags signTransaction as potentially malicious since it allows signing transactions for arbitrary networks. Sell flow now defaults to manual deposit instructions (copy address + memo). Buy flow keeps one-click send via sendTransaction which Phantom allows.
1 parent 04781ff commit 70c782d

File tree

1 file changed

+14
-34
lines changed

1 file changed

+14
-34
lines changed

frontend/src/components/Widget.tsx

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { PublicKey, Connection } from '@solana/web3.js';
66
import { api } from '../api';
77
import { useQuote } from '../hooks/useQuote';
88
import { useTxPoller } from '../hooks/useTxPoller';
9-
import { buildBuyTransaction, buildSellTransaction } from '../lib/transactions';
9+
import { buildBuyTransaction } from '../lib/transactions';
1010
import type { BuyResponse, SellResponse, Transaction } from '../types';
1111

1212
type Tab = 'buy' | 'sell';
@@ -65,7 +65,7 @@ function statusLabel(status: Transaction['status']): string {
6565

6666
export function Widget() {
6767
const { connection } = useConnection();
68-
const { publicKey, connected, sendTransaction, signTransaction } = useWallet();
68+
const { publicKey, connected, sendTransaction } = useWallet();
6969
const walletAddress = publicKey?.toBase58() ?? '';
7070
const { prices, getBuyQuote, getSellQuote } = useQuote();
7171
const { tx, polling, startPolling, reset: resetPoller } = useTxPoller();
@@ -160,7 +160,6 @@ export function Widget() {
160160
publicKey={publicKey}
161161
connection={connection}
162162
sendTransaction={sendTransaction}
163-
signTransaction={signTransaction}
164163
/>
165164
)}
166165

@@ -308,15 +307,13 @@ function DepositView({
308307
publicKey,
309308
connection,
310309
sendTransaction,
311-
signTransaction,
312310
}: {
313311
isBuy: boolean;
314312
order: BuyResponse | SellResponse;
315313
polling: boolean;
316314
publicKey: PublicKey;
317315
connection: Connection;
318316
sendTransaction: WalletContextState['sendTransaction'];
319-
signTransaction: WalletContextState['signTransaction'];
320317
}) {
321318
const [sending, setSending] = useState(false);
322319
const [sent, setSent] = useState(false);
@@ -328,41 +325,24 @@ function DepositView({
328325
: (order as SellResponse).amount_sol;
329326
const currency = isBuy ? 'USDC' : 'SOL';
330327

331-
// For sell flow, signTransaction is required. If wallet doesn't support it, force manual.
332-
const sellNeedsManual = !isBuy && !signTransaction;
328+
// Sell flow must use manual instructions — Phantom blocks signTransaction
329+
// as a security measure (flags it as potentially malicious dApp).
330+
const sellNeedsManual = !isBuy;
333331

334332
async function handleSend() {
335-
if (sending || sent) return;
333+
if (sending || sent || !isBuy) return;
336334
setSendError(null);
337335
setSending(true);
338336

339337
try {
340-
if (isBuy) {
341-
const tx = await buildBuyTransaction(
342-
connection,
343-
publicKey,
344-
order.deposit_address,
345-
(order as BuyResponse).usdc_cost,
346-
order.memo,
347-
);
348-
await sendTransaction(tx, connection);
349-
} else {
350-
if (!signTransaction) {
351-
throw new Error('Wallet does not support transaction signing. Use manual deposit.');
352-
}
353-
const { transaction, devnetConnection, lastValidBlockHeight } = await buildSellTransaction(
354-
publicKey,
355-
order.deposit_address,
356-
(order as SellResponse).amount_sol,
357-
order.memo,
358-
);
359-
const signed = await signTransaction(transaction);
360-
const sig = await devnetConnection.sendRawTransaction(signed.serialize());
361-
await devnetConnection.confirmTransaction(
362-
{ signature: sig, blockhash: transaction.recentBlockhash!, lastValidBlockHeight },
363-
'confirmed',
364-
);
365-
}
338+
const tx = await buildBuyTransaction(
339+
connection,
340+
publicKey,
341+
order.deposit_address,
342+
(order as BuyResponse).usdc_cost,
343+
order.memo,
344+
);
345+
await sendTransaction(tx, connection);
366346
setSent(true);
367347
} catch (err) {
368348
const message = err instanceof Error ? err.message : 'Transaction failed';

0 commit comments

Comments
 (0)