Apps/Feature #37: add onUserReject event handler (#1354)

* add onUserReject event handler

* fix invoking possibly undefined func

* update sdk version

* yarn lock update

* fix network passing
This commit is contained in:
Mikhail Mikheev 2020-09-15 20:21:03 +04:00 committed by GitHub
parent e000958c28
commit 8a6633db92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 918 additions and 53 deletions

View File

@ -164,7 +164,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"@gnosis.pm/safe-apps-sdk": "https://github.com/gnosis/safe-apps-sdk.git#development", "@gnosis.pm/safe-apps-sdk": "0.4.0",
"@gnosis.pm/safe-contracts": "1.1.1-dev.2", "@gnosis.pm/safe-contracts": "1.1.1-dev.2",
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#1bf397f", "@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#1bf397f",
"@gnosis.pm/util-contracts": "2.0.6", "@gnosis.pm/util-contracts": "2.0.6",

View File

@ -111,6 +111,7 @@ interface CreateTransactionArgs {
type CreateTransactionAction = ThunkAction<Promise<void>, AppReduxState, undefined, AnyAction> type CreateTransactionAction = ThunkAction<Promise<void>, AppReduxState, undefined, AnyAction>
type ConfirmEventHandler = (safeTxHash: string) => void type ConfirmEventHandler = (safeTxHash: string) => void
type RejectEventHandler = () => void
const createTransaction = ( const createTransaction = (
{ {
@ -125,6 +126,7 @@ const createTransaction = (
origin = null, origin = null,
}: CreateTransactionArgs, }: CreateTransactionArgs,
onUserConfirm?: ConfirmEventHandler, onUserConfirm?: ConfirmEventHandler,
onUserReject?: RejectEventHandler,
): CreateTransactionAction => async (dispatch: Dispatch, getState: () => AppReduxState): Promise<void> => { ): CreateTransactionAction => async (dispatch: Dispatch, getState: () => AppReduxState): Promise<void> => {
const state = getState() const state = getState()
@ -242,6 +244,21 @@ const createTransaction = (
dispatch(closeSnackbarAction({ key: pendingExecutionKey })) dispatch(closeSnackbarAction({ key: pendingExecutionKey }))
removeTxFromStore(mockedTx, safeAddress, dispatch, state) removeTxFromStore(mockedTx, safeAddress, dispatch, state)
console.error('Tx error: ', error) console.error('Tx error: ', error)
// Different wallets return different error messages in this case. This is an assumption that if
// error message includes "user" word, the tx was rejected by user
let errorIncludesUserWord = false
if (typeof error === 'string') {
errorIncludesUserWord = (error as string).includes('User') || (error as string).includes('user')
}
if (error.message) {
errorIncludesUserWord = error.message.includes('User') || error.message.includes('user')
}
if (errorIncludesUserWord) {
onUserReject?.()
}
}) })
.then(async (receipt) => { .then(async (receipt) => {
if (pendingExecutionKey) { if (pendingExecutionKey) {

View File

@ -71,6 +71,7 @@ type OwnProps = {
ethBalance: string ethBalance: string
onCancel: () => void onCancel: () => void
onUserConfirm: (safeTxHash: string) => void onUserConfirm: (safeTxHash: string) => void
onUserTxReject: () => void
onClose: () => void onClose: () => void
} }
@ -84,6 +85,7 @@ const ConfirmTransactionModal = ({
onCancel, onCancel,
onUserConfirm, onUserConfirm,
onClose, onClose,
onUserTxReject,
}: OwnProps): React.ReactElement | null => { }: OwnProps): React.ReactElement | null => {
const dispatch = useDispatch() const dispatch = useDispatch()
if (!isOpen) { if (!isOpen) {
@ -111,6 +113,7 @@ const ConfirmTransactionModal = ({
navigateToTransactionsTab: false, navigateToTransactionsTab: false,
}, },
handleUserConfirmation, handleUserConfirmation,
onUserTxReject,
), ),
) )
onClose() onClose()
@ -133,27 +136,25 @@ const ConfirmTransactionModal = ({
<> <>
<AddressInfo ethBalance={ethBalance} safeAddress={safeAddress} safeName={safeName} /> <AddressInfo ethBalance={ethBalance} safeAddress={safeAddress} safeName={safeName} />
<DividerLine withArrow /> <DividerLine withArrow />
{txs.map((tx, index) => { {txs.map((tx, index) => (
return ( <Wrapper key={index}>
<Wrapper key={index}> <Collapse description={<AddressInfo safeAddress={tx.to} />} title={`Transaction ${index + 1}`}>
<Collapse description={<AddressInfo safeAddress={tx.to} />} title={`Transaction ${index + 1}`}> <CollapseContent>
<CollapseContent> <div className="section">
<div className="section"> <Heading tag="h3">Value</Heading>
<Heading tag="h3">Value</Heading> <div className="value-section">
<div className="value-section"> <Img alt="Ether" height={40} src={getEthAsToken('0').logoUri} />
<Img alt="Ether" height={40} src={getEthAsToken('0').logoUri} /> <Bold>{humanReadableValue(tx.value, 18)} ETH</Bold>
<Bold>{humanReadableValue(tx.value, 18)} ETH</Bold>
</div>
</div> </div>
<div className="section"> </div>
<Heading tag="h3">Data (hex encoded)*</Heading> <div className="section">
<StyledTextBox>{tx.data}</StyledTextBox> <Heading tag="h3">Data (hex encoded)*</Heading>
</div> <StyledTextBox>{tx.data}</StyledTextBox>
</CollapseContent> </div>
</Collapse> </CollapseContent>
</Wrapper> </Collapse>
) </Wrapper>
})} ))}
</> </>
) )

View File

@ -8,6 +8,7 @@ import {
INTERFACE_MESSAGES, INTERFACE_MESSAGES,
RequestId, RequestId,
Transaction, Transaction,
LowercaseNetworks,
} from '@gnosis.pm/safe-apps-sdk' } from '@gnosis.pm/safe-apps-sdk'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { useEffect, useCallback, MutableRefObject } from 'react' import { useEffect, useCallback, MutableRefObject } from 'react'
@ -88,7 +89,7 @@ const useIframeMessageHandler = (
messageId: INTERFACE_MESSAGES.ON_SAFE_INFO, messageId: INTERFACE_MESSAGES.ON_SAFE_INFO,
data: { data: {
safeAddress: safeAddress as string, safeAddress: safeAddress as string,
network, network: network.toLowerCase() as LowercaseNetworks,
ethBalance: ethBalance as string, ethBalance: ethBalance as string,
}, },
} }

View File

@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useRef, useState, useMemo } from 'react' import React, { useCallback, useEffect, useRef, useState, useMemo } from 'react'
import { INTERFACE_MESSAGES, Transaction, RequestId } from '@gnosis.pm/safe-apps-sdk' import { INTERFACE_MESSAGES, Transaction, RequestId, LowercaseNetworks } from '@gnosis.pm/safe-apps-sdk'
import { Card, IconText, Loader, Menu, Title } from '@gnosis.pm/safe-react-components' import { Card, IconText, Loader, Menu, Title } from '@gnosis.pm/safe-react-components'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import styled, { css } from 'styled-components' import styled, { css } from 'styled-components'
@ -102,6 +102,13 @@ const Apps = (): React.ReactElement => {
) )
} }
const onUserTxReject = () => {
sendMessageToIframe(
{ messageId: INTERFACE_MESSAGES.TRANSACTION_REJECTED, data: {} },
confirmTransactionModal.requestId,
)
}
const onSelectApp = useCallback( const onSelectApp = useCallback(
(appId) => { (appId) => {
if (selectedAppId === appId) { if (selectedAppId === appId) {
@ -148,7 +155,7 @@ const Apps = (): React.ReactElement => {
messageId: INTERFACE_MESSAGES.ON_SAFE_INFO, messageId: INTERFACE_MESSAGES.ON_SAFE_INFO,
data: { data: {
safeAddress: safeAddress as string, safeAddress: safeAddress as string,
network, network: network.toLowerCase() as LowercaseNetworks,
ethBalance: ethBalance as string, ethBalance: ethBalance as string,
}, },
}) })
@ -208,6 +215,7 @@ const Apps = (): React.ReactElement => {
onCancel={closeConfirmationModal} onCancel={closeConfirmationModal}
onClose={closeConfirmationModal} onClose={closeConfirmationModal}
onUserConfirm={onUserTxConfirm} onUserConfirm={onUserTxConfirm}
onUserTxReject={onUserTxReject}
/> />
</> </>
) )

896
yarn.lock

File diff suppressed because it is too large Load Diff