From ce57e3c1e12b8879fdc044b2dc15579f47f8d0e3 Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Sun, 27 Sep 2020 22:03:12 -0700 Subject: [PATCH] Show transaction IDs, remove duplicate code --- src/components/LinkAddress.jsx | 1 + src/components/StandaloneBalancesDisplay.jsx | 25 ++- src/components/TradeForm.jsx | 12 +- .../UserInfoTable/AccountsTable.jsx | 37 ++-- .../UserInfoTable/BalancesTable.jsx | 40 +++-- .../UserInfoTable/OpenOrderTable.jsx | 12 +- src/utils/notifications.js | 13 ++ src/utils/send.js | 161 ++++-------------- 8 files changed, 127 insertions(+), 174 deletions(-) diff --git a/src/components/LinkAddress.jsx b/src/components/LinkAddress.jsx index b273f39..ae0829c 100644 --- a/src/components/LinkAddress.jsx +++ b/src/components/LinkAddress.jsx @@ -11,6 +11,7 @@ export default function LinkAddress({ title, address }) { icon={} href={'https://explorer.solana.com/address/' + address} target="_blank" + rel="noopener noreferrer" > {address} diff --git a/src/components/StandaloneBalancesDisplay.jsx b/src/components/StandaloneBalancesDisplay.jsx index 54c8188..4dc7ab9 100644 --- a/src/components/StandaloneBalancesDisplay.jsx +++ b/src/components/StandaloneBalancesDisplay.jsx @@ -14,6 +14,7 @@ import { useWallet } from '../utils/wallet'; import Link from './Link'; import { settleFunds } from '../utils/send'; import { useSendConnection } from '../utils/connection'; +import { notify } from '../utils/notifications'; const RowBox = styled(Row)` padding-bottom: 20px; @@ -45,14 +46,22 @@ export default function StandaloneBalancesDisplay() { balances && balances.find((b) => b.coin === quoteCurrency); async function onSettleFunds() { - return await settleFunds({ - market, - openOrders: openOrdersAccount, - connection, - wallet, - baseCurrencyAccount, - quoteCurrencyAccount, - }); + try { + await settleFunds({ + market, + openOrders: openOrdersAccount, + connection, + wallet, + baseCurrencyAccount, + quoteCurrencyAccount, + }); + } catch (e) { + notify({ + message: 'Error settling funds', + description: e.message, + type: 'error', + }); + } } return ( diff --git a/src/components/TradeForm.jsx b/src/components/TradeForm.jsx index cf0fe77..ad6110a 100644 --- a/src/components/TradeForm.jsx +++ b/src/components/TradeForm.jsx @@ -167,14 +167,16 @@ export default function TradeForm({ style, setChangeOrderRef }) { wallet, baseCurrencyAccount: baseCurrencyAccount?.pubkey, quoteCurrencyAccount: quoteCurrencyAccount?.pubkey, - onConfirmCallBack: () => { - setPrice(null); - onSetBaseSize(null); - }, }); + setPrice(null); + onSetBaseSize(null); } catch (e) { console.warn(e); - notify({ message: 'Error placing order: ' + e.message, type: 'error' }); + notify({ + message: 'Error placing order', + description: e.message, + type: 'error', + }); } finally { setSubmitting(false); } diff --git a/src/components/UserInfoTable/AccountsTable.jsx b/src/components/UserInfoTable/AccountsTable.jsx index 1751331..a140831 100644 --- a/src/components/UserInfoTable/AccountsTable.jsx +++ b/src/components/UserInfoTable/AccountsTable.jsx @@ -4,26 +4,35 @@ import DataTable from '../layout/DataTable'; import { useConnection } from '../../utils/connection'; import { useWallet } from '../../utils/wallet'; import { settleFunds } from '../../utils/send'; +import { notify } from '../../utils/notifications'; export default function AccountsTable({ accountBalances }) { const connection = useConnection(); const { wallet } = useWallet(); async function onSettleFunds(account) { - const { - market, - openOrdersAccount, - baseCurrencyAccount, - quoteCurrencyAccount, - } = account; - return await settleFunds({ - market, - openOrders: openOrdersAccount, - connection, - wallet, - baseCurrencyAccount, - quoteCurrencyAccount, - }); + try { + const { + market, + openOrdersAccount, + baseCurrencyAccount, + quoteCurrencyAccount, + } = account; + return await settleFunds({ + market, + openOrders: openOrdersAccount, + connection, + wallet, + baseCurrencyAccount, + quoteCurrencyAccount, + }); + } catch (e) { + notify({ + message: 'Error settling funds', + description: e.message, + type: 'error', + }); + } } const columns = [ diff --git a/src/components/UserInfoTable/BalancesTable.jsx b/src/components/UserInfoTable/BalancesTable.jsx index a65c757..0f63f81 100644 --- a/src/components/UserInfoTable/BalancesTable.jsx +++ b/src/components/UserInfoTable/BalancesTable.jsx @@ -8,6 +8,7 @@ import DataTable from '../layout/DataTable'; import { useSendConnection } from '../../utils/connection'; import { useWallet } from '../../utils/wallet'; import { settleFunds } from '../../utils/send'; +import { notify } from '../../utils/notifications'; export default function BalancesTable({ balances, @@ -20,21 +21,30 @@ export default function BalancesTable({ const { wallet } = useWallet(); async function onSettleFunds(market, openOrders) { - return await settleFunds({ - market, - openOrders, - connection, - wallet, - baseCurrencyAccount: getSelectedTokenAccountForMint( - accounts, - market?.baseMintAddress, - ), - quoteCurrencyAccount: getSelectedTokenAccountForMint( - accounts, - market?.quoteMintAddress, - ), - onSuccess: onSettleSuccess, - }); + try { + await settleFunds({ + market, + openOrders, + connection, + wallet, + baseCurrencyAccount: getSelectedTokenAccountForMint( + accounts, + market?.baseMintAddress, + ), + quoteCurrencyAccount: getSelectedTokenAccountForMint( + accounts, + market?.quoteMintAddress, + ), + }); + } catch (e) { + notify({ + message: 'Error settling funds', + description: e.message, + type: 'error', + }); + return; + } + onSettleSuccess && onSettleSuccess(); } const columns = [ diff --git a/src/components/UserInfoTable/OpenOrderTable.jsx b/src/components/UserInfoTable/OpenOrderTable.jsx index d49cae0..ca781f7 100644 --- a/src/components/UserInfoTable/OpenOrderTable.jsx +++ b/src/components/UserInfoTable/OpenOrderTable.jsx @@ -21,25 +21,25 @@ export default function OpenOrderTable({ openOrders, onCancelSuccess }) { const [cancelId, setCancelId] = useState(null); async function cancel(order) { + setCancelId(order?.orderId); try { await cancelOrder({ order, market: order.market, connection, wallet, - onBeforeSendCallBack: () => setCancelId(order?.orderId), - onConfirmCallBack: () => { - setCancelId(null); - onCancelSuccess && onCancelSuccess(); - }, }); } catch (e) { notify({ - message: 'Error cancelling order: ' + e.message, + message: 'Error cancelling order', + description: e.message, type: 'error', }); + return; + } finally { setCancelId(null); } + onCancelSuccess && onCancelSuccess(); } const columns = [ diff --git a/src/utils/notifications.js b/src/utils/notifications.js index 91d2357..a7820eb 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -1,12 +1,25 @@ import React from 'react'; import { notification } from 'antd'; +import Link from '../components/Link'; export function notify({ message, description, + txid, type = 'info', placement = 'bottomLeft', }) { + if (txid) { + description = ( + + View transaction {txid.slice(0, 8)}...{txid.slice(txid.length - 8)} + + ); + } notification[type]({ message: {message}, description: ( diff --git a/src/utils/send.js b/src/utils/send.js index 2c427f7..5ea2369 100644 --- a/src/utils/send.js +++ b/src/utils/send.js @@ -42,7 +42,6 @@ export async function settleFunds({ wallet, baseCurrencyAccount, quoteCurrencyAccount, - onSuccess, }) { if ( !market || @@ -121,32 +120,12 @@ export async function settleFunds({ ? [...settleFundsSigners, createAccountSigner] : settleFundsSigners; - const onConfirm = (result) => { - if (result.timeout) { - notify({ - message: 'Timed out', - type: 'error', - description: 'Timed out awaiting confirmation on transaction', - }); - } else if (result.err) { - console.log(result.err); - notify({ message: 'Error settling funds', type: 'error' }); - } else { - notify({ message: 'Fund settlement confirmed', type: 'success' }); - onSuccess && onSuccess(); - } - }; - const onBeforeSend = () => notify({ message: 'Settling funds...' }); - const onAfterSend = () => - notify({ message: 'Funds settled', type: 'success' }); return await sendTransaction({ transaction, signers, wallet, connection, - onBeforeSend, - onAfterSend, - onConfirm, + sendingMessage: 'Settling funds...', }); } @@ -154,15 +133,7 @@ export async function cancelOrder(params) { return cancelOrders({ ...params, orders: [params.order] }); } -export async function cancelOrders({ - market, - wallet, - connection, - orders, - onBeforeSendCallBack, - onAfterSendCallBack, - onConfirmCallBack, -}) { +export async function cancelOrders({ market, wallet, connection, orders }) { const transaction = market.makeMatchOrdersTransaction(5); orders.forEach((order) => { transaction.add( @@ -170,52 +141,11 @@ export async function cancelOrders({ ); }); transaction.add(market.makeMatchOrdersTransaction(5)); - const onConfirm = (result) => { - if (result.timeout) { - notify({ - message: 'Timed out', - type: 'error', - description: 'Timed out awaiting confirmation on transaction', - }); - } else if (result.err) { - console.log(result.err); - notify({ - message: - orders.length > 1 - ? 'Error cancelling orders' - : 'Error cancelling order', - type: 'error', - }); - } else { - notify({ - message: - orders.length > 1 - ? 'Order cancellations confirmed' - : 'Order cancellation confirmed', - type: 'success', - }); - } - onConfirmCallBack && onConfirmCallBack(); - }; - const onBeforeSend = () => { - notify({ message: 'Sending cancel...' }); - onBeforeSendCallBack && onBeforeSendCallBack(); - }; - const onAfterSend = () => { - notify({ - message: orders.length > 1 ? 'Orders cancelled' : 'Order cancelled', - type: 'success', - }); - onAfterSendCallBack && onAfterSendCallBack(); - }; - return await sendTransaction({ transaction, wallet, connection, - onBeforeSend, - onAfterSend, - onConfirm, + sendingMessage: 'Sending cancel...', }); } @@ -229,9 +159,6 @@ export async function placeOrder({ wallet, baseCurrencyAccount, quoteCurrencyAccount, - onBeforeSendCallBack, - onAfterSendCallBack, - onConfirmCallBack, }) { let formattedMinOrderSize = market?.minOrderSize?.toFixed(getDecimalCount(market.minOrderSize)) || @@ -313,38 +240,12 @@ export async function placeOrder({ transaction.add(placeOrderTx); transaction.add(market.makeMatchOrdersTransaction(5)); - const onConfirm = (result) => { - if (result.timeout) { - notify({ - message: 'Timed out', - type: 'error', - description: 'Timed out awaiting confirmation on transaction', - }); - } else if (result.err) { - console.log(result.err); - notify({ message: 'Error placing order', type: 'error' }); - } else { - notify({ message: 'Order confirmed', type: 'success' }); - } - onConfirmCallBack && onConfirmCallBack(); - }; - const onBeforeSend = () => { - notify({ message: 'Sending order...' }); - onBeforeSendCallBack && onBeforeSendCallBack(); - }; - const onAfterSend = () => { - notify({ message: 'Order sent', type: 'success' }); - onAfterSendCallBack && onAfterSendCallBack(); - }; - return await sendTransaction({ transaction, wallet, connection, - onBeforeSend, - onAfterSend, - onConfirm, signers, + sendingMessage: 'Sending order...', }); } @@ -359,9 +260,9 @@ async function sendTransaction({ wallet, signers = [wallet.publicKey], connection, - onBeforeSend, - onAfterSend, - onConfirm, + sendingMessage = 'Sending transaction...', + sentMessage = 'Transaction sent', + successMessage = 'Transaction confirmed', timeout = DEFAULT_TIMEOUT, }) { transaction.recentBlockhash = ( @@ -371,29 +272,36 @@ async function sendTransaction({ const rawTransaction = ( await wallet.signTransaction(transaction) ).serialize(); - let done = false; const startTime = getUnixTs(); - onBeforeSend(); + notify({ message: sendingMessage }); const txid = await connection.sendRawTransaction(rawTransaction, { skipPreflight: true, }); - onAfterSend(); - console.log('Started sending transaction for', txid); - awaitTransactionSignatureConfirmation(txid, timeout, connection) - .then((res) => { - done = true; - onConfirm(res); - }) - .catch((res) => { - done = true; - onConfirm(res); - }); - while (!done && getUnixTs() - startTime < timeout) { - connection.sendRawTransaction(rawTransaction, { - skipPreflight: true, - }); - await sleep(300); + notify({ message: sentMessage, type: 'success', txid }); + + console.log('Started awaiting confirmation for', txid); + + let done = false; + (async () => { + while (!done && getUnixTs() - startTime < timeout) { + connection.sendRawTransaction(rawTransaction, { + skipPreflight: true, + }); + await sleep(300); + } + })(); + try { + await awaitTransactionSignatureConfirmation(txid, timeout, connection); + } catch (err) { + if (err.timeout) { + throw new Error('Timed out awaiting confirmation on transaction'); + } + throw new Error('Transaction failed'); + } finally { + done = true; } + notify({ message: successMessage, type: 'success', txid }); + console.log('Latency', txid, getUnixTs() - startTime); return txid; } @@ -421,7 +329,7 @@ async function awaitTransactionSignatureConfirmation( console.log('WS confirmed', txid, result); done = true; if (result.err) { - reject(result); + reject(result.err); } else { resolve(result); } @@ -434,6 +342,7 @@ async function awaitTransactionSignatureConfirmation( console.log('WS error in setup', txid, e); } while (!done) { + // eslint-disable-next-line no-loop-func (async () => { try { const signatureStatuses = await connection.getSignatureStatuses([ @@ -446,7 +355,7 @@ async function awaitTransactionSignatureConfirmation( } else if (result.err) { console.log('REST error for', txid, result); done = true; - reject(result); + reject(result.err); } else if (!result.confirmations) { console.log('REST no confirmations for', txid, result); } else {