From d7965aa88bd851e4f1636d8f1da50d11209f2963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Thu, 27 Mar 2025 11:23:52 -0300 Subject: [PATCH 01/12] fix: undefine socket after disconnecting --- paybutton-config-server.json | 5 +++++ react/lib/components/Widget/Widget.tsx | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 paybutton-config-server.json diff --git a/paybutton-config-server.json b/paybutton-config-server.json new file mode 100644 index 00000000..bb1b2a69 --- /dev/null +++ b/paybutton-config-server.json @@ -0,0 +1,5 @@ +{ + "wsBaseUrl": "https://socket.paybutton.org", + "apiBaseUrl": "https://paybutton.org", + "altpaymentClient": "sideshift" +} diff --git a/react/lib/components/Widget/Widget.tsx b/react/lib/components/Widget/Widget.tsx index 56fbc332..4a86e062 100644 --- a/react/lib/components/Widget/Widget.tsx +++ b/react/lib/components/Widget/Widget.tsx @@ -390,6 +390,7 @@ export const Widget: React.FunctionComponent = props => { const setupAltpaymentSocket = async (): Promise => { if (altpaymentSocket !== undefined) { altpaymentSocket.disconnect(); + setAltpaymentSocket(undefined); } const newSocket = io(`${wsBaseUrl ?? config.wsBaseUrl}/altpayment`, { forceNew: true, @@ -411,6 +412,7 @@ export const Widget: React.FunctionComponent = props => { void getAddressDetails(to, apiBaseUrl); if (socket !== undefined) { socket.disconnect(); + setSocket(undefined); } const newSocket = io(`${wsBaseUrl ?? config.wsBaseUrl}/addresses`, { forceNew: true, @@ -426,15 +428,18 @@ export const Widget: React.FunctionComponent = props => { await setupAltpaymentSocket() } else if (altpaymentSocket) { altpaymentSocket.disconnect() + setAltpaymentSocket(undefined); } })() return () => { if (socket !== undefined) { socket.disconnect(); + setSocket(undefined); } if (altpaymentSocket !== undefined) { altpaymentSocket.disconnect(); + setAltpaymentSocket(undefined); } } }, [to, useAltpayment]); From 4cf73efe25fbaff1d8a0ad3f27cbb6b878c79bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Fri, 4 Apr 2025 12:23:41 -0300 Subject: [PATCH 02/12] feat: socket state variables created on paybutton --- react/lib/components/PayButton/PayButton.tsx | 86 +++++- .../PaymentDialog/PaymentDialog.tsx | 73 +++++ react/lib/components/Widget/Widget.tsx | 270 +++++++++++------- .../lib/components/Widget/WidgetContainer.tsx | 18 +- react/lib/util/socket.ts | 78 ++++- 5 files changed, 397 insertions(+), 128 deletions(-) diff --git a/react/lib/components/PayButton/PayButton.tsx b/react/lib/components/PayButton/PayButton.tsx index 9206cf34..848ed725 100644 --- a/react/lib/components/PayButton/PayButton.tsx +++ b/react/lib/components/PayButton/PayButton.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import { Theme, ThemeName, ThemeProvider, useTheme } from '../../themes'; import Button, { ButtonProps } from '../Button/Button'; +import { Socket } from 'socket.io-client'; import { Transaction, @@ -14,9 +15,13 @@ import { CurrencyObject, generatePaymentId, getCurrencyObject, - isPropsTrue + isPropsTrue, + setupAltpaymentSocket, + setupTxsSocket, + CryptoCurrency } from '../../util'; import { PaymentDialog } from '../PaymentDialog'; +import { AltpaymentCoin, AltpaymentError, AltpaymentPair, AltpaymentShift } from '../../altpayment'; export interface PayButtonProps extends ButtonProps { to: string; amount?: number | string; @@ -53,10 +58,20 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { const [disabled, setDisabled] = useState(false); const [errorMsg, setErrorMsg] = useState(''); const [amount, setAmount] = useState(props.amount); + const [txsSocket, setTxsSocket] = useState(undefined); + const [altpaymentSocket, setAltpaymentSocket] = useState(undefined); + const [useAltpayment, setUseAltpayment] = useState(false); + const [coins, setCoins] = useState([]); + const [loadingPair, setLoadingPair] = useState(false); + const [coinPair, setCoinPair] = useState(); + const [loadingShift, setLoadingShift] = useState(false); + const [altpaymentShift, setAltpaymentShift] = useState(); + const [altpaymentError, setAltpaymentError] = useState(undefined); const [currencyObj, setCurrencyObj] = useState(); const [cryptoAmount, setCryptoAmount] = useState(); const [price, setPrice] = useState(0); + const [newTxs, setNewTxs] = useState(); const priceRef = useRef(price); const cryptoAmountRef = useRef(cryptoAmount); @@ -87,6 +102,9 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { } = Object.assign({}, PayButton.defaultProps, props); const [paymentId] = useState(!disablePaymentId ? generatePaymentId(8) : undefined); + const [addressType, setAddressType] = useState( + getCurrencyTypeFromAddress(to), + ); useEffect(() => { priceRef.current = price; @@ -151,6 +169,49 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { } }, [to]); + useEffect(() => { + if (dialogOpen === false) { + return + } + (async () => { + if (txsSocket === undefined) { + await setupTxsSocket({ + address: to, + txsSocket, + apiBaseUrl, + wsBaseUrl, + setTxsSocket, + setNewTxs, + }) + } + if (altpaymentSocket === undefined && useAltpayment) { + await setupAltpaymentSocket({ + addressType, + altpaymentSocket, + wsBaseUrl, + setAltpaymentSocket, + setCoins, + setCoinPair, + setLoadingPair, + setAltpaymentShift, + setLoadingShift, + setAltpaymentError, + }) + } + })() + + return () => { + if (txsSocket !== undefined) { + txsSocket.disconnect(); + setTxsSocket(undefined); + } + if (altpaymentSocket !== undefined) { + altpaymentSocket.disconnect(); + setAltpaymentSocket(undefined); + } + } + }, [to, useAltpayment, dialogOpen]); + useEffect(() => { if (dialogOpen === false && props.amount && currency) { const obj = getCurrencyObject( @@ -233,6 +294,7 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { editable={editable} goalAmount={goalAmount} dialogOpen={dialogOpen} + setDialogOpen={setDialogOpen} onClose={handleCloseDialog} wsBaseUrl={wsBaseUrl} apiBaseUrl={apiBaseUrl} @@ -240,6 +302,28 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { disableAltpayment={disableAltpayment} contributionOffset={contributionOffset} autoClose={autoClose} + useAltpayment={useAltpayment} + setUseAltpayment={setUseAltpayment} + setTxsSocket={setTxsSocket} + txsSocket={txsSocket} + setAltpaymentSocket={setAltpaymentSocket} + altpaymentSocket={altpaymentSocket} + setCoins={setCoins} + coins={coins} + setCoinPair={setCoinPair} + coinPair={coinPair} + setLoadingPair={setLoadingPair} + loadingPair={loadingPair} + setAltpaymentShift={setAltpaymentShift} + altpaymentShift={altpaymentShift} + setLoadingShift={setLoadingShift} + loadingShift={loadingShift} + setAltpaymentError={setAltpaymentError} + altpaymentError={altpaymentError} + addressType={addressType} + setAddressType={setAddressType} + setNewTxs={setNewTxs} + newTxs={newTxs} /> {errorMsg && (

{ @@ -82,6 +130,9 @@ export const PaymentDialog = ( setSuccess(false); }; const handleSuccess = (transaction: Transaction): void => { + if (dialogOpen === false) { + setDialogOpen(true) + } setSuccess(true); onSuccess?.(transaction); setTimeout(() => { @@ -154,6 +205,28 @@ export const PaymentDialog = ( hoverText={hoverText} disableAltpayment={disableAltpayment} contributionOffset={contributionOffset} + useAltpayment={useAltpayment} + setUseAltpayment={setUseAltpayment} + setTxsSocket={setTxsSocket} + txsSocket={txsSocket} + setAltpaymentSocket={setAltpaymentSocket} + altpaymentSocket={altpaymentSocket} + setCoins={setCoins} + coins={coins} + setCoinPair={setCoinPair} + coinPair={coinPair} + setLoadingPair={setLoadingPair} + loadingPair={loadingPair} + setAltpaymentShift={setAltpaymentShift} + altpaymentShift={altpaymentShift} + setLoadingShift={setLoadingShift} + loadingShift={loadingShift} + setAltpaymentError={setAltpaymentError} + altpaymentError={altpaymentError} + addressType={addressType} + setAddressType={setAddressType} + setNewTxs={setNewTxs} + newTxs={newTxs} foot={success && ( = props => { animation, randomSatoshis = false, editable, - setNewTxs, newTxs, + setNewTxs, apiBaseUrl, usdPrice, wsBaseUrl, hoverText = Button.defaultProps.hoverText, setAltpaymentShift, altpaymentShift, - useAltpayment, - setUseAltpayment, shiftCompleted, setShiftCompleted, disableAltpayment, - contributionOffset + contributionOffset, + useAltpayment, + setUseAltpayment, + setTxsSocket, + txsSocket, + setAltpaymentSocket, + altpaymentSocket, + addressType, + setAddressType, + coins, + setCoins, + coinPair, + setCoinPair, + loadingPair, + setLoadingPair, + loadingShift, + setLoadingShift, + altpaymentError, + setAltpaymentError } = Object.assign({}, Widget.defaultProps, props); const [loading, setLoading] = useState(true); + + // Define controlled websocket constants if standalone widget + + const [internalTxsSocket, setInternalTxsSocket] = useState(undefined); + const thisTxsSocket = txsSocket ?? internalTxsSocket + const setThisTxsSocket = setTxsSocket ?? setInternalTxsSocket + + const [internalNewTxs, setInternalNewTxs] = useState(); + const thisNewTxs = newTxs ?? internalNewTxs + const setThisNewTxs = setNewTxs ?? setInternalNewTxs + + const [internalAltpaymentShift, setInternalAltpaymentShift] = useState(undefined); + const thisAltpaymentShift = altpaymentShift ?? internalAltpaymentShift; + const setThisAltpaymentShift = setAltpaymentShift ?? setInternalAltpaymentShift; + + const [internalUseAltpayment, setInternalUseAltpayment] = useState(false); + const thisUseAltpayment = useAltpayment ?? internalUseAltpayment; + const setThisUseAltpayment = setUseAltpayment ?? setInternalUseAltpayment; + + const [internalAltpaymentSocket, setInternalAltpaymentSocket] = useState(undefined); + const thisAltpaymentSocket = altpaymentSocket ?? internalAltpaymentSocket; + const setThisAltpaymentSocket = setAltpaymentSocket ?? setInternalAltpaymentSocket; + + const [internalShiftCompleted, setInternalShiftCompleted] = useState(false); + const thisShiftCompleted = shiftCompleted ?? internalShiftCompleted; + const setThisShiftCompleted = setShiftCompleted ?? setInternalShiftCompleted; + + const [internalCoins, setInternalCoins] = useState([]); + const thisCoins = coins ?? internalCoins; + const setThisCoins = setCoins ?? setInternalCoins; + + const [internalCoinPair, setInternalCoinPair] = useState(); + const thisCoinPair = coinPair ?? internalCoinPair; + const setThisCoinPair = setCoinPair ?? setInternalCoinPair; + + const [internalLoadingPair, setInternalLoadingPair] = useState(false); + const thisLoadingPair = loadingPair ?? internalLoadingPair; + const setThisLoadingPair = setLoadingPair ?? setInternalLoadingPair; + + const [internalLoadingShift, setInternalLoadingShift] = useState(false); + const thisLoadingShift = loadingShift ?? internalLoadingShift; + const setThisLoadingShift = setLoadingShift ?? setInternalLoadingShift; + + const [internalAltpaymentError, setInternalAltpaymentError] = useState(); + const thisAltpaymentError = altpaymentError ?? internalAltpaymentError; + const setThisAltpaymentError = setAltpaymentError ?? setInternalAltpaymentError; + + const [internalAddressType, setInternalAddressType] = useState(getCurrencyTypeFromAddress(to)); + const thisAddressType = addressType ?? internalAddressType; + const setThisAddressType = setAddressType ?? setInternalAddressType; + const [copied, setCopied] = useState(false); const [recentlyCopied, setRecentlyCopied] = useState(false); const [totalReceived, setTotalReceived] = useState( @@ -323,25 +403,15 @@ export const Widget: React.FunctionComponent = props => { const [errorMsg, setErrorMsg] = useState(''); const [goalText, setGoalText] = useState(''); const [goalPercent, setGoalPercent] = useState(0); - const [socket, setSocket] = useState(undefined); - const [addressType, setAddressType] = useState( - getCurrencyTypeFromAddress(to), - ); + const [altpaymentEditable, setAltpaymentEditable] = useState(false); const price = props.price ?? 0; const [url, setUrl] = useState(''); const [userEditedAmount, setUserEditedAmount] = useState(); - const [text, setText] = useState(`Send any amount of ${addressType}`); + const [text, setText] = useState(`Send any amount of ${thisAddressType}`); const [widgetButtonText, setWidgetButtonText] = useState('Send Payment'); const [opReturn, setOpReturn] = useState(); - const [altpaymentSocket, setAltpaymentSocket] = useState(undefined); - const [coins, setCoins] = useState([]); - const [loadingPair, setLoadingPair] = useState(false); - const [coinPair, setCoinPair] = useState(); - const [loadingShift, setLoadingShift] = useState(false); - const [altpaymentError, setAltpaymentError] = useState(undefined); - const [altpaymentEditable, setAltpaymentEditable] = useState(false); const [isAboveMinimumAltpaymentAmount, setIsAboveMinimumAltpaymentAmount] = useState(null); const theme = useTheme(props.theme, isValidXecAddress(to)); @@ -387,66 +457,48 @@ export const Widget: React.FunctionComponent = props => { }, [price]) useEffect(() => { - const setupAltpaymentSocket = async (): Promise => { - if (altpaymentSocket !== undefined) { - altpaymentSocket.disconnect(); - setAltpaymentSocket(undefined); - } - const newSocket = io(`${wsBaseUrl ?? config.wsBaseUrl}/altpayment`, { - forceNew: true, - }); - setAltpaymentSocket(newSocket); - altpaymentListener({ - addressType, - socket: newSocket, - setCoins, - setCoinPair, - setLoadingPair, - setAltpaymentShift, - setLoadingShift, - setAltpaymentError, + (async () => { + if (thisTxsSocket === undefined) { + await setupTxsSocket({ + address: to, + txsSocket: thisTxsSocket, + apiBaseUrl, + wsBaseUrl, + setTxsSocket: setThisTxsSocket, + setNewTxs: setThisNewTxs, }) } - - const setupTxsSocket = async (): Promise => { - void getAddressDetails(to, apiBaseUrl); - if (socket !== undefined) { - socket.disconnect(); - setSocket(undefined); - } - const newSocket = io(`${wsBaseUrl ?? config.wsBaseUrl}/addresses`, { - forceNew: true, - query: { addresses: [getAddressPrefixed(to)] }, - }); - setSocket(newSocket); - txsListener(newSocket, setNewTxs); + if (thisAltpaymentSocket === undefined && thisUseAltpayment) { + await setupAltpaymentSocket({ + addressType: thisAddressType, + wsBaseUrl, + altpaymentSocket: thisAltpaymentSocket, + setAltpaymentSocket: setThisAltpaymentSocket, + setCoins: setThisCoins, + setCoinPair: setThisCoinPair, + setLoadingPair: setThisLoadingPair, + setAltpaymentShift: setThisAltpaymentShift, + setLoadingShift: setThisLoadingShift, + setAltpaymentError: setThisAltpaymentError, + }) } - - (async () => { - await setupTxsSocket() - if (useAltpayment) { - await setupAltpaymentSocket() - } else if (altpaymentSocket) { - altpaymentSocket.disconnect() - setAltpaymentSocket(undefined); - } })() return () => { - if (socket !== undefined) { - socket.disconnect(); - setSocket(undefined); + if (thisTxsSocket !== undefined) { + thisTxsSocket.disconnect(); + setThisTxsSocket(undefined); } - if (altpaymentSocket !== undefined) { - altpaymentSocket.disconnect(); - setAltpaymentSocket(undefined); + if (thisAltpaymentSocket !== undefined) { + thisAltpaymentSocket.disconnect(); + setThisAltpaymentSocket(undefined); } } - }, [to, useAltpayment]); + }, [to, thisUseAltpayment]); const tradeWithAltpayment = () => { - if (setUseAltpayment) { - setUseAltpayment(true) + if (setThisUseAltpayment) { + setThisUseAltpayment(true) } } @@ -465,7 +517,7 @@ export const Widget: React.FunctionComponent = props => { setTotalReceived(balance); setLoading(false); })(); - }, [newTxs]); + }, [thisNewTxs]); useEffect(() => { const invalidAmount = @@ -518,13 +570,13 @@ export const Widget: React.FunctionComponent = props => { } } - if (userEditedAmount !== undefined && thisAmount && addressType) { + if (userEditedAmount !== undefined && thisAmount && thisAddressType) { const obj = getCurrencyObject(+thisAmount, currency, false); setThisCurrencyObject(obj); if (props.setCurrencyObject) { props.setCurrencyObject(obj); } - } else if (thisAmount && addressType) { + } else if (thisAmount && thisAddressType) { cleanAmount = +thisAmount; const obj = getCurrencyObject(cleanAmount, currency, randomSatoshis); setThisCurrencyObject(obj); @@ -538,27 +590,25 @@ export const Widget: React.FunctionComponent = props => { if (to === undefined) { return; } - const address = to; let url; - const addressType: Currency = getCurrencyTypeFromAddress(address); - setAddressType(addressType); - setWidgetButtonText(`Send with ${addressType} wallet`); + setThisAddressType(thisAddressType); + setWidgetButtonText(`Send with ${thisAddressType} wallet`); if (thisCurrencyObject && hasPrice) { const convertedAmount = thisCurrencyObject.float / price const convertedObj = price ? getCurrencyObject( convertedAmount, - addressType, + thisAddressType, randomSatoshis, ) : null; if (convertedObj) { setText( - `Send ${thisCurrencyObject.string} ${thisCurrencyObject.currency} = ${convertedObj.string} ${addressType}`, + `Send ${thisCurrencyObject.string} ${thisCurrencyObject.currency} = ${convertedObj.string} ${thisAddressType}`, ); - url = resolveUrl(addressType, convertedObj.float); + url = resolveUrl(thisAddressType, convertedObj.float); setUrl(url ?? ""); } } else { @@ -569,8 +619,8 @@ export const Widget: React.FunctionComponent = props => { setText(`Send ${thisCurrencyObject.string} ${currency}`); url = resolveUrl(currency, thisCurrencyObject?.float); } else { - setText(`Send any amount of ${addressType}`); - url = resolveUrl(addressType); + setText(`Send any amount of ${thisAddressType}`); + url = resolveUrl(thisAddressType); } setUrl(url ?? ""); } @@ -640,7 +690,7 @@ export const Widget: React.FunctionComponent = props => { }, [totalReceived, currency, goalAmount, price, hasPrice, contributionOffset]); const handleButtonClick = () => { - if (addressType === 'XEC') { + if (thisAddressType === 'XEC') { const hasExtension = getCashtabProviderStatus(); if (!hasExtension) { const webUrl = `https://cashtab.com/#/send?bip21=${url}`; @@ -772,28 +822,28 @@ export const Widget: React.FunctionComponent = props => { position="relative" > {// Altpayment region - useAltpayment && + thisUseAltpayment && } @@ -909,7 +959,7 @@ export const Widget: React.FunctionComponent = props => { onClick={isAboveMinimumAltpaymentAmount || altpaymentEditable ? tradeWithAltpayment : undefined} style={{cursor: isAboveMinimumAltpaymentAmount || altpaymentEditable ? 'pointer' : 'default'}} > - Don't have any {addressType}? + Don't have any {thisAddressType}? )} diff --git a/react/lib/components/Widget/WidgetContainer.tsx b/react/lib/components/Widget/WidgetContainer.tsx index 88fdd083..13a45e33 100644 --- a/react/lib/components/Widget/WidgetContainer.tsx +++ b/react/lib/components/Widget/WidgetContainer.tsx @@ -1,6 +1,6 @@ import { OptionsObject, SnackbarProvider, useSnackbar } from 'notistack'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { AltpaymentShift, getAltpaymentClient } from '../../altpayment'; +import { getAltpaymentClient } from '../../altpayment'; import successSound from '../../assets/success.mp3.json'; @@ -22,7 +22,7 @@ import { import Widget, { WidgetProps } from './Widget'; export interface WidgetContainerProps - extends Omit { + extends Omit { active?: boolean; amount?: number; opReturn?: string; @@ -46,6 +46,7 @@ export interface WidgetContainerProps successText?: string; disableAltpayment?: boolean contributionOffset?: number + setNewTxs: Function } const snackbarOptions: OptionsObject = { @@ -106,6 +107,11 @@ export const WidgetContainer: React.FunctionComponent = hoverText, disableAltpayment, contributionOffset, + altpaymentShift, + setAltpaymentShift, + newTxs, + setNewTxs, + txsSocket, ...widgetProps } = props; @@ -123,9 +129,6 @@ export const WidgetContainer: React.FunctionComponent = const [success, setSuccess] = useState(false); const { enqueueSnackbar } = useSnackbar(); - const [newTxs, setNewTxs] = useState(); - const [useAltpayment, setUseAltpayment] = useState(false); - const [altpaymentShift, setAltpaymentShift] = useState(); const [shiftCompleted, setShiftCompleted] = useState(false); const paymentClient = getAltpaymentClient() @@ -269,16 +272,15 @@ export const WidgetContainer: React.FunctionComponent = success={success} disabled={disabled} editable={editable} - setNewTxs={setNewTxs} newTxs={newTxs} + setNewTxs={setNewTxs} + txsSocket={txsSocket} wsBaseUrl={wsBaseUrl} apiBaseUrl={apiBaseUrl} successText={successText} hoverText={hoverText} altpaymentShift={altpaymentShift} setAltpaymentShift={setAltpaymentShift} - useAltpayment={useAltpayment} - setUseAltpayment={setUseAltpayment} shiftCompleted={shiftCompleted} setShiftCompleted={setShiftCompleted} disableAltpayment={disableAltpayment} diff --git a/react/lib/util/socket.ts b/react/lib/util/socket.ts index b089ca2b..d10bbf47 100644 --- a/react/lib/util/socket.ts +++ b/react/lib/util/socket.ts @@ -1,10 +1,13 @@ -import { Socket } from 'socket.io-client'; +import { io, Socket } from 'socket.io-client'; import { AltpaymentCoin, AltpaymentError, AltpaymentPair, AltpaymentShift } from '../altpayment'; +import config from '../../../paybutton-config.json'; import { BroadcastTxData } from './types'; +import { getAddressDetails } from './api-client'; +import { getAddressPrefixed } from './address'; -export const txsListener = (socket: Socket, setNewTxs: Function): void => { - socket.on('incoming-txs', (broadcastedTxData: BroadcastTxData) => { +export const txsListener = (txsSocket: Socket, setNewTxs: Function): void => { + txsSocket.on('incoming-txs', (broadcastedTxData: BroadcastTxData) => { const unconfirmedTxs = broadcastedTxData.txs.filter( tx => tx.confirmed === false, ); @@ -19,7 +22,7 @@ export const txsListener = (socket: Socket, setNewTxs: Function): void => { interface AltpaymentListenerParams { addressType: string - socket: Socket + altpaymentSocket: Socket setCoins: Function setCoinPair: Function setLoadingPair: Function @@ -29,25 +32,82 @@ interface AltpaymentListenerParams { } export const altpaymentListener = (params: AltpaymentListenerParams): void => { - params.socket.on('send-altpayment-coins-info', (coins: AltpaymentCoin[]) => { + params.altpaymentSocket.on('send-altpayment-coins-info', (coins: AltpaymentCoin[]) => { params.setCoins(coins.filter(c => c.coin !== params.addressType)) }) - params.socket.on('shift-creation-error', (error: AltpaymentError) => { + params.altpaymentSocket.on('shift-creation-error', (error: AltpaymentError) => { params.setAltpaymentError(error) params.setLoadingShift(false) return }); - params.socket.on('quote-creation-error', (error: AltpaymentError) => { + params.altpaymentSocket.on('quote-creation-error', (error: AltpaymentError) => { params.setAltpaymentError(error) params.setLoadingShift(false) return }); - params.socket.on('shift-created', (shift: AltpaymentShift) => { + params.altpaymentSocket.on('shift-created', (shift: AltpaymentShift) => { params.setAltpaymentShift(shift) params.setLoadingShift(false) }); - params.socket.on('send-altpayment-rate', (pair: AltpaymentPair) => { + params.altpaymentSocket.on('send-altpayment-rate', (pair: AltpaymentPair) => { params.setCoinPair(pair) params.setLoadingPair(false) }) }; + +interface SetupAltpaymentSocketParams { + addressType: string + altpaymentSocket?: Socket + wsBaseUrl?: string + setAltpaymentSocket: Function + setCoins: Function + setCoinPair: Function + setLoadingPair: Function + setAltpaymentShift: Function + setLoadingShift: Function + setAltpaymentError: Function +} + +export const setupAltpaymentSocket = async (params: SetupAltpaymentSocketParams): Promise => { + if (params.altpaymentSocket !== undefined) { + params.altpaymentSocket.disconnect(); + params.setAltpaymentSocket(undefined); + } + const newSocket = io(`${params.wsBaseUrl ?? config.wsBaseUrl}/altpayment`, { + forceNew: true, + }); + params.setAltpaymentSocket(newSocket); + altpaymentListener({ + addressType: params.addressType, + altpaymentSocket: newSocket, + setCoins: params.setCoins, + setCoinPair: params.setCoinPair, + setLoadingPair: params.setLoadingPair, + setAltpaymentShift: params.setAltpaymentShift, + setLoadingShift: params.setLoadingShift, + setAltpaymentError: params.setAltpaymentError, + }) +} + +interface SetupTxsSocketParams { + address: string + txsSocket?: Socket + apiBaseUrl?: string + wsBaseUrl?: string + setTxsSocket: Function + setNewTxs: Function +} + +export const setupTxsSocket = async (params: SetupTxsSocketParams): Promise => { + void getAddressDetails(params.address, params.apiBaseUrl); + if (params.txsSocket !== undefined) { + params.txsSocket.disconnect(); + params.setTxsSocket(undefined); + } + const newSocket = io(`${params.wsBaseUrl ?? config.wsBaseUrl}/addresses`, { + forceNew: true, + query: { addresses: [getAddressPrefixed(params.address)] }, + }); + params.setTxsSocket(newSocket); + txsListener(newSocket, params.setNewTxs); +} From 5351976b2aed5efbdce509356a31c473de09d1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Fri, 11 Apr 2025 17:31:25 -0300 Subject: [PATCH 03/12] wip --- react/lib/components/PayButton/PayButton.tsx | 9 ++++++++- .../lib/components/PaymentDialog/PaymentDialog.tsx | 2 ++ react/lib/components/Widget/Widget.tsx | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/react/lib/components/PayButton/PayButton.tsx b/react/lib/components/PayButton/PayButton.tsx index 848ed725..9d6c3e89 100644 --- a/react/lib/components/PayButton/PayButton.tsx +++ b/react/lib/components/PayButton/PayButton.tsx @@ -54,6 +54,7 @@ export interface PayButtonProps extends ButtonProps { } export const PayButton = (props: PayButtonProps): React.ReactElement => { + console.log('render PB') const [dialogOpen, setDialogOpen] = useState(false); const [disabled, setDisabled] = useState(false); const [errorMsg, setErrorMsg] = useState(''); @@ -170,11 +171,13 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { }, [to]); useEffect(() => { + console.log('efeitou paybas'); if (dialogOpen === false) { return } (async () => { if (txsSocket === undefined) { + console.log('setup txs paybas'); await setupTxsSocket({ address: to, txsSocket, @@ -185,6 +188,7 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { }) } if (altpaymentSocket === undefined && useAltpayment) { + console.log('setup alt paybas'); await setupAltpaymentSocket({ addressType, altpaymentSocket, @@ -201,16 +205,19 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { })() return () => { + console.log('cleanup paybas'); if (txsSocket !== undefined) { + console.log('cleanup txs paybas'); txsSocket.disconnect(); setTxsSocket(undefined); } if (altpaymentSocket !== undefined) { + console.log('cleanup alt paybas'); altpaymentSocket.disconnect(); setAltpaymentSocket(undefined); } } - }, [to, useAltpayment, dialogOpen]); + }, []); useEffect(() => { if (dialogOpen === false && props.amount && currency) { diff --git a/react/lib/components/PaymentDialog/PaymentDialog.tsx b/react/lib/components/PaymentDialog/PaymentDialog.tsx index 078410b0..94f684dc 100644 --- a/react/lib/components/PaymentDialog/PaymentDialog.tsx +++ b/react/lib/components/PaymentDialog/PaymentDialog.tsx @@ -130,7 +130,9 @@ export const PaymentDialog = ( setSuccess(false); }; const handleSuccess = (transaction: Transaction): void => { + console.log('handling succs') if (dialogOpen === false) { + console.log('opening dialog') setDialogOpen(true) } setSuccess(true); diff --git a/react/lib/components/Widget/Widget.tsx b/react/lib/components/Widget/Widget.tsx index 3dfc85ab..9858b5ad 100644 --- a/react/lib/components/Widget/Widget.tsx +++ b/react/lib/components/Widget/Widget.tsx @@ -362,34 +362,42 @@ export const Widget: React.FunctionComponent = props => { const thisUseAltpayment = useAltpayment ?? internalUseAltpayment; const setThisUseAltpayment = setUseAltpayment ?? setInternalUseAltpayment; + //A const [internalAltpaymentSocket, setInternalAltpaymentSocket] = useState(undefined); const thisAltpaymentSocket = altpaymentSocket ?? internalAltpaymentSocket; const setThisAltpaymentSocket = setAltpaymentSocket ?? setInternalAltpaymentSocket; + //A const [internalShiftCompleted, setInternalShiftCompleted] = useState(false); const thisShiftCompleted = shiftCompleted ?? internalShiftCompleted; const setThisShiftCompleted = setShiftCompleted ?? setInternalShiftCompleted; + //A const [internalCoins, setInternalCoins] = useState([]); const thisCoins = coins ?? internalCoins; const setThisCoins = setCoins ?? setInternalCoins; + //A const [internalCoinPair, setInternalCoinPair] = useState(); const thisCoinPair = coinPair ?? internalCoinPair; const setThisCoinPair = setCoinPair ?? setInternalCoinPair; + //A const [internalLoadingPair, setInternalLoadingPair] = useState(false); const thisLoadingPair = loadingPair ?? internalLoadingPair; const setThisLoadingPair = setLoadingPair ?? setInternalLoadingPair; + //A const [internalLoadingShift, setInternalLoadingShift] = useState(false); const thisLoadingShift = loadingShift ?? internalLoadingShift; const setThisLoadingShift = setLoadingShift ?? setInternalLoadingShift; + //A const [internalAltpaymentError, setInternalAltpaymentError] = useState(); const thisAltpaymentError = altpaymentError ?? internalAltpaymentError; const setThisAltpaymentError = setAltpaymentError ?? setInternalAltpaymentError; + //A const [internalAddressType, setInternalAddressType] = useState(getCurrencyTypeFromAddress(to)); const thisAddressType = addressType ?? internalAddressType; const setThisAddressType = setAddressType ?? setInternalAddressType; @@ -457,8 +465,10 @@ export const Widget: React.FunctionComponent = props => { }, [price]) useEffect(() => { + console.log('efeitrou widget'); (async () => { if (thisTxsSocket === undefined) { + console.log('asettingup txssocket widget', { to, thisTxsSocket, apiBaseUrl, wsBaseUrl, setThisTxsSocket, setNewTxs}) await setupTxsSocket({ address: to, txsSocket: thisTxsSocket, @@ -469,6 +479,7 @@ export const Widget: React.FunctionComponent = props => { }) } if (thisAltpaymentSocket === undefined && thisUseAltpayment) { + console.log('settingup altpay widget') await setupAltpaymentSocket({ addressType: thisAddressType, wsBaseUrl, @@ -485,11 +496,14 @@ export const Widget: React.FunctionComponent = props => { })() return () => { + console.log('cleanup widget') if (thisTxsSocket !== undefined) { + console.log('cleanup txs widget') thisTxsSocket.disconnect(); setThisTxsSocket(undefined); } if (thisAltpaymentSocket !== undefined) { + console.log('cleanup alt widget') thisAltpaymentSocket.disconnect(); setThisAltpaymentSocket(undefined); } From 7607d3cfca24edcae2e2f9587d9fc6492a2be64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Tue, 15 Apr 2025 11:40:29 -0300 Subject: [PATCH 04/12] feat: isChild props --- react/lib/components/PaymentDialog/PaymentDialog.tsx | 1 + react/lib/components/Widget/Widget.tsx | 6 ++++-- react/lib/components/Widget/WidgetContainer.tsx | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/react/lib/components/PaymentDialog/PaymentDialog.tsx b/react/lib/components/PaymentDialog/PaymentDialog.tsx index 94f684dc..0559e72c 100644 --- a/react/lib/components/PaymentDialog/PaymentDialog.tsx +++ b/react/lib/components/PaymentDialog/PaymentDialog.tsx @@ -180,6 +180,7 @@ export const PaymentDialog = ( transitionDuration={{ enter: 300, exit: 300 }} > = props => { loadingShift, setLoadingShift, altpaymentError, - setAltpaymentError + setAltpaymentError, + isChild } = Object.assign({}, Widget.defaultProps, props); const [loading, setLoading] = useState(true); @@ -467,7 +469,7 @@ export const Widget: React.FunctionComponent = props => { useEffect(() => { console.log('efeitrou widget'); (async () => { - if (thisTxsSocket === undefined) { + if (isChild !== true) { console.log('asettingup txssocket widget', { to, thisTxsSocket, apiBaseUrl, wsBaseUrl, setThisTxsSocket, setNewTxs}) await setupTxsSocket({ address: to, diff --git a/react/lib/components/Widget/WidgetContainer.tsx b/react/lib/components/Widget/WidgetContainer.tsx index 13a45e33..5bb5efc0 100644 --- a/react/lib/components/Widget/WidgetContainer.tsx +++ b/react/lib/components/Widget/WidgetContainer.tsx @@ -112,6 +112,7 @@ export const WidgetContainer: React.FunctionComponent = newTxs, setNewTxs, txsSocket, + isChild, ...widgetProps } = props; @@ -255,6 +256,7 @@ export const WidgetContainer: React.FunctionComponent = Date: Tue, 15 Apr 2025 11:41:16 -0300 Subject: [PATCH 05/12] feat: setDialogOpen --- react/lib/components/PayButton/PayButton.tsx | 3 ++- react/lib/util/socket.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/react/lib/components/PayButton/PayButton.tsx b/react/lib/components/PayButton/PayButton.tsx index 9d6c3e89..6d1807c9 100644 --- a/react/lib/components/PayButton/PayButton.tsx +++ b/react/lib/components/PayButton/PayButton.tsx @@ -185,6 +185,7 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { wsBaseUrl, setTxsSocket, setNewTxs, + setDialogOpen }) } if (altpaymentSocket === undefined && useAltpayment) { @@ -217,7 +218,7 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { setAltpaymentSocket(undefined); } } - }, []); + }, [dialogOpen]); useEffect(() => { if (dialogOpen === false && props.amount && currency) { diff --git a/react/lib/util/socket.ts b/react/lib/util/socket.ts index d10bbf47..b06ba977 100644 --- a/react/lib/util/socket.ts +++ b/react/lib/util/socket.ts @@ -6,7 +6,7 @@ import { BroadcastTxData } from './types'; import { getAddressDetails } from './api-client'; import { getAddressPrefixed } from './address'; -export const txsListener = (txsSocket: Socket, setNewTxs: Function): void => { +const txsListener = (txsSocket: Socket, setNewTxs: Function, setDialogOpen?: Function): void => { txsSocket.on('incoming-txs', (broadcastedTxData: BroadcastTxData) => { const unconfirmedTxs = broadcastedTxData.txs.filter( tx => tx.confirmed === false, @@ -15,6 +15,9 @@ export const txsListener = (txsSocket: Socket, setNewTxs: Function): void => { broadcastedTxData.messageType === 'NewTx' && unconfirmedTxs.length !== 0 ) { + if (setDialogOpen !== undefined) { + setDialogOpen(true) + } setNewTxs(unconfirmedTxs); } }); @@ -96,6 +99,7 @@ interface SetupTxsSocketParams { wsBaseUrl?: string setTxsSocket: Function setNewTxs: Function + setDialogOpen?: Function } export const setupTxsSocket = async (params: SetupTxsSocketParams): Promise => { @@ -109,5 +113,5 @@ export const setupTxsSocket = async (params: SetupTxsSocketParams): Promise Date: Tue, 15 Apr 2025 15:15:15 -0300 Subject: [PATCH 06/12] fix: altpayment recreation on widget --- react/lib/components/Widget/Widget.tsx | 50 +++++++++++++------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/react/lib/components/Widget/Widget.tsx b/react/lib/components/Widget/Widget.tsx index fb508338..4ddf6777 100644 --- a/react/lib/components/Widget/Widget.tsx +++ b/react/lib/components/Widget/Widget.tsx @@ -469,32 +469,30 @@ export const Widget: React.FunctionComponent = props => { useEffect(() => { console.log('efeitrou widget'); (async () => { - if (isChild !== true) { - console.log('asettingup txssocket widget', { to, thisTxsSocket, apiBaseUrl, wsBaseUrl, setThisTxsSocket, setNewTxs}) - await setupTxsSocket({ - address: to, - txsSocket: thisTxsSocket, - apiBaseUrl, - wsBaseUrl, - setTxsSocket: setThisTxsSocket, - setNewTxs: setThisNewTxs, - }) - } - if (thisAltpaymentSocket === undefined && thisUseAltpayment) { - console.log('settingup altpay widget') - await setupAltpaymentSocket({ - addressType: thisAddressType, - wsBaseUrl, - altpaymentSocket: thisAltpaymentSocket, - setAltpaymentSocket: setThisAltpaymentSocket, - setCoins: setThisCoins, - setCoinPair: setThisCoinPair, - setLoadingPair: setThisLoadingPair, - setAltpaymentShift: setThisAltpaymentShift, - setLoadingShift: setThisLoadingShift, - setAltpaymentError: setThisAltpaymentError, - }) - } + if (isChild !== true) { + await setupTxsSocket({ + address: to, + txsSocket: thisTxsSocket, + apiBaseUrl, + wsBaseUrl, + setTxsSocket: setThisTxsSocket, + setNewTxs: setThisNewTxs, + }) + if (thisUseAltpayment) { + await setupAltpaymentSocket({ + addressType: thisAddressType, + wsBaseUrl, + altpaymentSocket: thisAltpaymentSocket, + setAltpaymentSocket: setThisAltpaymentSocket, + setCoins: setThisCoins, + setCoinPair: setThisCoinPair, + setLoadingPair: setThisLoadingPair, + setAltpaymentShift: setThisAltpaymentShift, + setLoadingShift: setThisLoadingShift, + setAltpaymentError: setThisAltpaymentError, + }) + } + } })() return () => { From 8e877f846fb73dac412541cbe086e7b49a4ed4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Tue, 15 Apr 2025 15:16:30 -0300 Subject: [PATCH 07/12] Revert: wip --- react/lib/components/PayButton/PayButton.tsx | 7 ------- react/lib/components/PaymentDialog/PaymentDialog.tsx | 2 -- react/lib/components/Widget/Widget.tsx | 12 ------------ 3 files changed, 21 deletions(-) diff --git a/react/lib/components/PayButton/PayButton.tsx b/react/lib/components/PayButton/PayButton.tsx index 6d1807c9..0bc74298 100644 --- a/react/lib/components/PayButton/PayButton.tsx +++ b/react/lib/components/PayButton/PayButton.tsx @@ -54,7 +54,6 @@ export interface PayButtonProps extends ButtonProps { } export const PayButton = (props: PayButtonProps): React.ReactElement => { - console.log('render PB') const [dialogOpen, setDialogOpen] = useState(false); const [disabled, setDisabled] = useState(false); const [errorMsg, setErrorMsg] = useState(''); @@ -171,13 +170,11 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { }, [to]); useEffect(() => { - console.log('efeitou paybas'); if (dialogOpen === false) { return } (async () => { if (txsSocket === undefined) { - console.log('setup txs paybas'); await setupTxsSocket({ address: to, txsSocket, @@ -189,7 +186,6 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { }) } if (altpaymentSocket === undefined && useAltpayment) { - console.log('setup alt paybas'); await setupAltpaymentSocket({ addressType, altpaymentSocket, @@ -206,14 +202,11 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { })() return () => { - console.log('cleanup paybas'); if (txsSocket !== undefined) { - console.log('cleanup txs paybas'); txsSocket.disconnect(); setTxsSocket(undefined); } if (altpaymentSocket !== undefined) { - console.log('cleanup alt paybas'); altpaymentSocket.disconnect(); setAltpaymentSocket(undefined); } diff --git a/react/lib/components/PaymentDialog/PaymentDialog.tsx b/react/lib/components/PaymentDialog/PaymentDialog.tsx index 0559e72c..2867faad 100644 --- a/react/lib/components/PaymentDialog/PaymentDialog.tsx +++ b/react/lib/components/PaymentDialog/PaymentDialog.tsx @@ -130,9 +130,7 @@ export const PaymentDialog = ( setSuccess(false); }; const handleSuccess = (transaction: Transaction): void => { - console.log('handling succs') if (dialogOpen === false) { - console.log('opening dialog') setDialogOpen(true) } setSuccess(true); diff --git a/react/lib/components/Widget/Widget.tsx b/react/lib/components/Widget/Widget.tsx index 4ddf6777..6c2af7e8 100644 --- a/react/lib/components/Widget/Widget.tsx +++ b/react/lib/components/Widget/Widget.tsx @@ -364,42 +364,34 @@ export const Widget: React.FunctionComponent = props => { const thisUseAltpayment = useAltpayment ?? internalUseAltpayment; const setThisUseAltpayment = setUseAltpayment ?? setInternalUseAltpayment; - //A const [internalAltpaymentSocket, setInternalAltpaymentSocket] = useState(undefined); const thisAltpaymentSocket = altpaymentSocket ?? internalAltpaymentSocket; const setThisAltpaymentSocket = setAltpaymentSocket ?? setInternalAltpaymentSocket; - //A const [internalShiftCompleted, setInternalShiftCompleted] = useState(false); const thisShiftCompleted = shiftCompleted ?? internalShiftCompleted; const setThisShiftCompleted = setShiftCompleted ?? setInternalShiftCompleted; - //A const [internalCoins, setInternalCoins] = useState([]); const thisCoins = coins ?? internalCoins; const setThisCoins = setCoins ?? setInternalCoins; - //A const [internalCoinPair, setInternalCoinPair] = useState(); const thisCoinPair = coinPair ?? internalCoinPair; const setThisCoinPair = setCoinPair ?? setInternalCoinPair; - //A const [internalLoadingPair, setInternalLoadingPair] = useState(false); const thisLoadingPair = loadingPair ?? internalLoadingPair; const setThisLoadingPair = setLoadingPair ?? setInternalLoadingPair; - //A const [internalLoadingShift, setInternalLoadingShift] = useState(false); const thisLoadingShift = loadingShift ?? internalLoadingShift; const setThisLoadingShift = setLoadingShift ?? setInternalLoadingShift; - //A const [internalAltpaymentError, setInternalAltpaymentError] = useState(); const thisAltpaymentError = altpaymentError ?? internalAltpaymentError; const setThisAltpaymentError = setAltpaymentError ?? setInternalAltpaymentError; - //A const [internalAddressType, setInternalAddressType] = useState(getCurrencyTypeFromAddress(to)); const thisAddressType = addressType ?? internalAddressType; const setThisAddressType = setAddressType ?? setInternalAddressType; @@ -467,7 +459,6 @@ export const Widget: React.FunctionComponent = props => { }, [price]) useEffect(() => { - console.log('efeitrou widget'); (async () => { if (isChild !== true) { await setupTxsSocket({ @@ -496,14 +487,11 @@ export const Widget: React.FunctionComponent = props => { })() return () => { - console.log('cleanup widget') if (thisTxsSocket !== undefined) { - console.log('cleanup txs widget') thisTxsSocket.disconnect(); setThisTxsSocket(undefined); } if (thisAltpaymentSocket !== undefined) { - console.log('cleanup alt widget') thisAltpaymentSocket.disconnect(); setThisAltpaymentSocket(undefined); } From 8df7328dee0497aca3f35f96c3210111f4c32cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Tue, 15 Apr 2025 15:19:58 -0300 Subject: [PATCH 08/12] chore: delete temp server config --- paybutton-config-server.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 paybutton-config-server.json diff --git a/paybutton-config-server.json b/paybutton-config-server.json deleted file mode 100644 index bb1b2a69..00000000 --- a/paybutton-config-server.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "wsBaseUrl": "https://socket.paybutton.org", - "apiBaseUrl": "https://paybutton.org", - "altpaymentClient": "sideshift" -} From 9f6c90a47f17bf28d6b3eb1ecd73fdd8d9a77e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Wed, 16 Apr 2025 15:18:50 -0300 Subject: [PATCH 09/12] fix: sideshift load --- react/lib/components/PayButton/PayButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/lib/components/PayButton/PayButton.tsx b/react/lib/components/PayButton/PayButton.tsx index 0bc74298..0740ac93 100644 --- a/react/lib/components/PayButton/PayButton.tsx +++ b/react/lib/components/PayButton/PayButton.tsx @@ -211,7 +211,7 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { setAltpaymentSocket(undefined); } } - }, [dialogOpen]); + }, [dialogOpen, useAltpayment]); useEffect(() => { if (dialogOpen === false && props.amount && currency) { From c6d6eafe3a4abb821dca5a5122e7d59a45880088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Fri, 9 May 2025 11:04:49 -0300 Subject: [PATCH 10/12] feat: wait a little if dialog has to open --- react/lib/util/socket.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/react/lib/util/socket.ts b/react/lib/util/socket.ts index b06ba977..f1214dc2 100644 --- a/react/lib/util/socket.ts +++ b/react/lib/util/socket.ts @@ -17,8 +17,12 @@ const txsListener = (txsSocket: Socket, setNewTxs: Function, setDialogOpen?: Fun ) { if (setDialogOpen !== undefined) { setDialogOpen(true) + setTimeout(() => { + setNewTxs(unconfirmedTxs); + }, 700); + } else { + setNewTxs(unconfirmedTxs); } - setNewTxs(unconfirmedTxs); } }); }; From 98b2989fc176c92b9489e529c6a8ab5e31ec59fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Mon, 26 May 2025 17:14:06 -0300 Subject: [PATCH 11/12] fix: shouldTriggerSuccess shouldn't be async --- .../lib/components/Widget/WidgetContainer.tsx | 2 +- react/lib/tests/util/validate.test.ts | 104 +++++++++--------- react/lib/util/validate.ts | 16 +-- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/react/lib/components/Widget/WidgetContainer.tsx b/react/lib/components/Widget/WidgetContainer.tsx index 0325c1bc..9cd43de7 100644 --- a/react/lib/components/Widget/WidgetContainer.tsx +++ b/react/lib/components/Widget/WidgetContainer.tsx @@ -163,7 +163,7 @@ export const WidgetContainer: React.FunctionComponent = const expectedAmount = currencyObj ? currencyObj?.float : undefined const receivedAmount = resolveNumber(transaction.amount); - if (await shouldTriggerOnSuccess( + if (shouldTriggerOnSuccess( transaction, currency, thisPrice, diff --git a/react/lib/tests/util/validate.test.ts b/react/lib/tests/util/validate.test.ts index e97452cb..79523efe 100644 --- a/react/lib/tests/util/validate.test.ts +++ b/react/lib/tests/util/validate.test.ts @@ -8,7 +8,7 @@ global.fetch = jest.fn(); describe('Validate Util Tests', () => { describe('shouldTriggerOnSuccess', () => { - + it('true when amount, opReturn, and paymentId match the ones received in transaction', async () => { const transaction: Transaction = { amount: '100.00', @@ -24,8 +24,8 @@ describe('Validate Util Tests', () => { const expectedPaymentId = '123'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -35,10 +35,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(true); }); - + it('true when paymentId is undefined and received paymentId is empty', async () => { const transaction: Transaction = { amount: '101.00', @@ -54,8 +54,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn message'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -65,10 +65,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(true); }); - + it('true when both expected and received paymentId are empty', async () => { const transaction: Transaction = { amount: '101.00', @@ -84,8 +84,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn message'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -95,10 +95,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(true); }); - + it('false when paymentId does not match received paymentId', async () => { const transaction: Transaction = { amount: '100.00', @@ -114,8 +114,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn message'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -125,10 +125,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(false); }); - + it('false when amount does not match received amount', async () => { const transaction: Transaction = { amount: '101.00', @@ -144,8 +144,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn message'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -155,10 +155,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(false); }); - + it('false when opReturn message does not match received message', async () => { const transaction: Transaction = { amount: '101.00', @@ -174,8 +174,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -185,10 +185,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(false); }); - + it('should ignore amount validation when expected amount is undefined', async () => { const transaction: Transaction = { amount: '101.00', @@ -204,8 +204,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -215,10 +215,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(true); }); - + it('should ignore paymentId validation when disablePaymentId is true', async () => { const transaction: Transaction = { amount: '101.00', @@ -234,8 +234,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -245,10 +245,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(true); }); - + it('false when opReturn is undefined and received opReturn message is not empty or undefined', async () => { const transaction: Transaction = { amount: '101.00', @@ -264,8 +264,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = undefined; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -275,10 +275,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(false); }); - + it('true when opReturn is in a different format than received opReturn message but rawMessage matches expected opReturn', async () => { const transaction: Transaction = { amount: '101.00', @@ -297,8 +297,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'classOf=2013 bullYears=2013|2017|2021'; const price = 1; const currency = 'XEC'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -308,10 +308,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(true); }); - + it('false when currency is USD and currencyObject is missing', async () => { const transaction: Transaction = { amount: '101.00', @@ -327,8 +327,8 @@ describe('Validate Util Tests', () => { const expectedOpReturn = 'test opReturn'; const price = 1; const currency = 'USD'; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -338,10 +338,10 @@ describe('Validate Util Tests', () => { expectedAmount, expectedOpReturn ); - + expect(result).toBe(false); }); - + it('true when currency is USD and currencyObject is provided', async () => { const transaction: Transaction = { amount: '3152585.12', @@ -362,8 +362,8 @@ describe('Validate Util Tests', () => { string: '$100', float: 100, }; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -374,7 +374,7 @@ describe('Validate Util Tests', () => { expectedOpReturn, currencyObject ); - + expect(result).toBe(true); }); @@ -398,8 +398,8 @@ describe('Validate Util Tests', () => { string: '$100', float: 100, }; - - const result = await shouldTriggerOnSuccess( + + const result = shouldTriggerOnSuccess( transaction, currency, price, @@ -410,9 +410,9 @@ describe('Validate Util Tests', () => { expectedOpReturn, currencyObject ); - + expect(result).toBe(true); }); }); }); - \ No newline at end of file + diff --git a/react/lib/util/validate.ts b/react/lib/util/validate.ts index 221c3e53..874af6f9 100644 --- a/react/lib/util/validate.ts +++ b/react/lib/util/validate.ts @@ -4,7 +4,7 @@ import { resolveNumber } from "./number"; import { Currency, CurrencyObject, Transaction } from "./types"; import { DECIMALS } from "./constants"; -export const shouldTriggerOnSuccess = async ( +export const shouldTriggerOnSuccess = ( transaction: Transaction, currency: string, price: number, @@ -19,9 +19,9 @@ export const shouldTriggerOnSuccess = async ( paymentId, rawMessage:rawOpReturn, message, - amount, - address } = transaction; - + amount, + address } = transaction; + let isAmountValid = true; if(expectedAmount) { @@ -41,19 +41,19 @@ export const shouldTriggerOnSuccess = async ( } } let isPaymentIdValid = true - let isOpReturnValid = true + let isOpReturnValid = true if(!randomSatoshis || randomSatoshis === 0){ const paymentIdsMatch = expectedPaymentId === paymentId; isPaymentIdValid = disablePaymentId ? true : paymentIdsMatch; - + const rawOpReturnIsEmptyOrUndefined = rawOpReturn === '' || rawOpReturn === undefined; const opReturn = rawOpReturnIsEmptyOrUndefined ? message : rawOpReturn const opReturnIsEmptyOrUndefined = opReturn === '' || opReturn === undefined; - + const opReturnsMatch = opReturn === expectedOpReturn; isOpReturnValid = expectedOpReturn ? opReturnsMatch : opReturnIsEmptyOrUndefined; } return isAmountValid && isPaymentIdValid && isOpReturnValid; -}; \ No newline at end of file +}; From 861816a5bee0471e1643b0b35e85ae3808e5388f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o?= Date: Mon, 26 May 2025 18:51:46 -0300 Subject: [PATCH 12/12] feat: check success before reopening dialog --- react/lib/components/PayButton/PayButton.tsx | 13 +++++++- react/lib/util/socket.ts | 33 +++++++++++++++----- react/lib/util/types.ts | 12 +++++++ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/react/lib/components/PayButton/PayButton.tsx b/react/lib/components/PayButton/PayButton.tsx index 4e49eb77..cc274821 100644 --- a/react/lib/components/PayButton/PayButton.tsx +++ b/react/lib/components/PayButton/PayButton.tsx @@ -176,6 +176,7 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { } (async () => { if (txsSocket === undefined) { + const expectedAmount = currencyObj ? currencyObj?.float : undefined await setupTxsSocket({ address: to, txsSocket, @@ -183,7 +184,17 @@ export const PayButton = (props: PayButtonProps): React.ReactElement => { wsBaseUrl, setTxsSocket, setNewTxs, - setDialogOpen + setDialogOpen, + checkSuccessInfo: { + currency, + price, + randomSatoshis: randomSatoshis ?? false, + disablePaymentId, + expectedAmount, + expectedOpReturn: opReturn, + expectedPaymentId: paymentId, + currencyObj, + } }) } if (altpaymentSocket === undefined && useAltpayment) { diff --git a/react/lib/util/socket.ts b/react/lib/util/socket.ts index f1214dc2..c522a527 100644 --- a/react/lib/util/socket.ts +++ b/react/lib/util/socket.ts @@ -2,11 +2,12 @@ import { io, Socket } from 'socket.io-client'; import { AltpaymentCoin, AltpaymentError, AltpaymentPair, AltpaymentShift } from '../altpayment'; import config from '../../../paybutton-config.json'; -import { BroadcastTxData } from './types'; +import { BroadcastTxData, CheckSuccessInfo } from './types'; import { getAddressDetails } from './api-client'; import { getAddressPrefixed } from './address'; +import { shouldTriggerOnSuccess } from './validate'; -const txsListener = (txsSocket: Socket, setNewTxs: Function, setDialogOpen?: Function): void => { +const txsListener = (txsSocket: Socket, setNewTxs: Function, setDialogOpen?: Function, checkSuccessInfo?: CheckSuccessInfo): void => { txsSocket.on('incoming-txs', (broadcastedTxData: BroadcastTxData) => { const unconfirmedTxs = broadcastedTxData.txs.filter( tx => tx.confirmed === false, @@ -15,11 +16,26 @@ const txsListener = (txsSocket: Socket, setNewTxs: Function, setDialogOpen?: Fun broadcastedTxData.messageType === 'NewTx' && unconfirmedTxs.length !== 0 ) { - if (setDialogOpen !== undefined) { - setDialogOpen(true) - setTimeout(() => { - setNewTxs(unconfirmedTxs); - }, 700); + if (setDialogOpen !== undefined && checkSuccessInfo !== undefined) { + for (const tx of unconfirmedTxs) { + if (shouldTriggerOnSuccess( + tx, + checkSuccessInfo.currency, + checkSuccessInfo.price, + checkSuccessInfo.randomSatoshis, + checkSuccessInfo.disablePaymentId, + checkSuccessInfo.expectedPaymentId, + checkSuccessInfo.expectedAmount, + checkSuccessInfo.expectedOpReturn, + checkSuccessInfo.currencyObj + )) { + setDialogOpen(true) + setTimeout(() => { + setNewTxs(unconfirmedTxs); + }, 700); + break + } + } } else { setNewTxs(unconfirmedTxs); } @@ -104,6 +120,7 @@ interface SetupTxsSocketParams { setTxsSocket: Function setNewTxs: Function setDialogOpen?: Function + checkSuccessInfo?: CheckSuccessInfo } export const setupTxsSocket = async (params: SetupTxsSocketParams): Promise => { @@ -117,5 +134,5 @@ export const setupTxsSocket = async (params: SetupTxsSocketParams): Promise