Feature: Send env info message on safe apps sdk initialization (#1349)

This commit is contained in:
Mikhail Mikheev 2020-09-22 22:01:55 +04:00 committed by GitHub
parent 59dc1f711c
commit eebe972bac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 48 additions and 63 deletions

View File

@ -111,7 +111,7 @@ interface CreateTransactionArgs {
type CreateTransactionAction = ThunkAction<Promise<void>, AppReduxState, undefined, AnyAction>
type ConfirmEventHandler = (safeTxHash: string) => void
type RejectEventHandler = () => void
type ErrorEventHandler = () => void
const createTransaction = (
{
@ -126,7 +126,7 @@ const createTransaction = (
origin = null,
}: CreateTransactionArgs,
onUserConfirm?: ConfirmEventHandler,
onUserReject?: RejectEventHandler,
onError?: ErrorEventHandler,
): CreateTransactionAction => async (dispatch: Dispatch, getState: () => AppReduxState): Promise<void> => {
const state = getState()
@ -172,6 +172,7 @@ const createTransaction = (
sender: from,
sigs,
}
const safeTxHash = generateSafeTxHash(safeAddress, txArgs)
try {
// Here we're checking that safe contract version is greater or equal 1.1.1, but
@ -179,20 +180,19 @@ const createTransaction = (
const canTryOffchainSigning =
!isExecution && !smartContractWallet && semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
if (canTryOffchainSigning) {
const signature = await tryOffchainSigning({ ...txArgs, safeAddress }, hardwareWallet)
const signature = await tryOffchainSigning(safeTxHash, { ...txArgs, safeAddress }, hardwareWallet)
if (signature) {
dispatch(closeSnackbarAction({ key: beforeExecutionKey }))
dispatch(enqueueSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded))
dispatch(fetchTransactions(safeAddress))
await saveTxToHistory({ ...txArgs, signature, origin })
dispatch(enqueueSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded))
dispatch(fetchTransactions(safeAddress))
onUserConfirm?.(safeTxHash)
return
}
}
const safeTxHash = generateSafeTxHash(safeAddress, txArgs)
const tx = isExecution
? await getExecutionTransaction(txArgs)
: await getApprovalTransaction(safeInstance, safeTxHash)
@ -245,20 +245,7 @@ const createTransaction = (
removeTxFromStore(mockedTx, safeAddress, dispatch, state)
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?.()
}
onError?.()
})
.then(async (receipt) => {
if (pendingExecutionKey) {

View File

@ -78,7 +78,7 @@ const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddres
const canTryOffchainSigning =
!isExecution && !smartContractWallet && semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
if (canTryOffchainSigning) {
const signature = await tryOffchainSigning({ ...txArgs, safeAddress }, hardwareWallet)
const signature = await tryOffchainSigning(tx.safeTxHash, { ...txArgs, safeAddress }, hardwareWallet)
if (signature) {
dispatch(closeSnackbarAction(beforeExecutionKey))

View File

@ -103,7 +103,7 @@ const notificationsMiddleware = (store) => (next) => async (action) => {
}
case ADD_INCOMING_TRANSACTIONS: {
action.payload.forEach((incomingTransactions, safeAddress) => {
const { latestIncomingTxBlock } = state.safes.get('safes').get(safeAddress)
const { latestIncomingTxBlock } = state.safes.get('safes').get(safeAddress, {})
const viewedSafes = state.currentSession['viewedSafes']
const recurringUser = viewedSafes?.includes(safeAddress)

View File

@ -1,5 +1,6 @@
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
import { AbstractProvider } from 'web3-core'
import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
const EIP712_NOT_SUPPORTED_ERROR_MSG = "EIP712 is not supported by user's wallet"
@ -59,7 +60,7 @@ const generateTypedDataFrom = async ({
}
export const getEIP712Signer = (version?: string) => async (txArgs) => {
const web3: any = getWeb3()
const web3 = getWeb3()
const typedData = await generateTypedDataFrom(txArgs)
let method = 'eth_signTypedData_v3'
@ -80,13 +81,14 @@ export const getEIP712Signer = (version?: string) => async (txArgs) => {
}
return new Promise((resolve, reject) => {
web3.currentProvider.sendAsync(signedTypedData, (err, signature) => {
const provider = web3.currentProvider as AbstractProvider
provider.sendAsync(signedTypedData, (err, signature) => {
if (err) {
reject(err)
return
}
if (signature.result == null) {
if (signature?.result == null) {
reject(new Error(EIP712_NOT_SUPPORTED_ERROR_MSG))
return
}

View File

@ -4,26 +4,13 @@ import { AbstractProvider } from 'web3-core/types'
const ETH_SIGN_NOT_SUPPORTED_ERROR_MSG = 'ETH_SIGN_NOT_SUPPORTED'
export const ethSigner = async ({
baseGas,
data,
gasPrice,
gasToken,
nonce,
operation,
refundReceiver,
safeInstance,
safeTxGas,
sender,
to,
valueInWei,
}): Promise<string> => {
type EthSignerArgs = {
safeTxHash: string
sender: string
}
export const ethSigner = async ({ safeTxHash, sender }: EthSignerArgs): Promise<string> => {
const web3 = await getWeb3()
const txHash = await safeInstance.methods
.getTransactionHash(to, valueInWei, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, nonce)
.call({
from: sender,
})
return new Promise(function (resolve, reject) {
const provider = web3.currentProvider as AbstractProvider
@ -31,7 +18,7 @@ export const ethSigner = async ({
{
jsonrpc: '2.0',
method: 'eth_sign',
params: [sender, txHash],
params: [sender, safeTxHash],
id: new Date().getTime(),
},
async function (err, signature) {

View File

@ -8,7 +8,7 @@ import { ethSigner } from './ethSigner'
const SIGNERS = {
EIP712_V3: getEIP712Signer('v3'),
EIP712_V4: getEIP712Signer('v4'),
EIP712: getEIP712Signer() as any,
EIP712: getEIP712Signer(),
ETH_SIGN: ethSigner,
}
@ -18,13 +18,13 @@ const getSignersByWallet = (isHW) =>
export const SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES = '>=1.1.1'
export const tryOffchainSigning = async (txArgs, isHW) => {
export const tryOffchainSigning = async (safeTxHash: string, txArgs, isHW: boolean): Promise<string> => {
let signature
const signerByWallet = getSignersByWallet(isHW)
for (const signingFunc of signerByWallet) {
try {
signature = await signingFunc(txArgs)
signature = await signingFunc({ ...txArgs, safeTxHash })
break
} catch (err) {

View File

@ -69,9 +69,8 @@ type OwnProps = {
safeAddress: string
safeName: string
ethBalance: string
onCancel: () => void
onUserConfirm: (safeTxHash: string) => void
onUserTxReject: () => void
onTxReject: () => void
onClose: () => void
}
@ -82,16 +81,20 @@ const ConfirmTransactionModal = ({
safeAddress,
ethBalance,
safeName,
onCancel,
onUserConfirm,
onClose,
onUserTxReject,
onTxReject,
}: OwnProps): React.ReactElement | null => {
const dispatch = useDispatch()
if (!isOpen) {
return null
}
const handleTxRejection = () => {
onTxReject()
onClose()
}
const handleUserConfirmation = (safeTxHash: string): void => {
onUserConfirm(safeTxHash)
onClose()
@ -113,10 +116,9 @@ const ConfirmTransactionModal = ({
navigateToTransactionsTab: false,
},
handleUserConfirmation,
onUserTxReject,
handleTxRejection,
),
)
onClose()
}
const areTxsMalformed = txs.some((t) => !isTxValid(t))
@ -165,13 +167,13 @@ const ConfirmTransactionModal = ({
footer={
<ModalFooterConfirmation
cancelText="Cancel"
handleCancel={onCancel}
handleCancel={handleTxRejection}
handleOk={confirmTransactions}
okDisabled={areTxsMalformed}
okText="Submit"
/>
}
onClose={onClose}
onClose={handleTxRejection}
/>
)
}

View File

@ -12,6 +12,7 @@ import {
} from '@gnosis.pm/safe-apps-sdk'
import { useDispatch, useSelector } from 'react-redux'
import { useEffect, useCallback, MutableRefObject } from 'react'
import { getTxServiceHost } from 'src/config/'
import {
safeEthBalanceSelector,
safeNameSelector,
@ -85,7 +86,7 @@ const useIframeMessageHandler = (
}
case SDK_MESSAGES.SAFE_APP_SDK_INITIALIZED: {
const message = {
const safeInfoMessage = {
messageId: INTERFACE_MESSAGES.ON_SAFE_INFO,
data: {
safeAddress: safeAddress as string,
@ -93,8 +94,15 @@ const useIframeMessageHandler = (
ethBalance: ethBalance as string,
},
}
const envInfoMessage = {
messageId: INTERFACE_MESSAGES.ENV_INFO,
data: {
txServiceUrl: getTxServiceHost(),
},
}
sendMessageToIframe(message)
sendMessageToIframe(safeInfoMessage)
sendMessageToIframe(envInfoMessage)
break
}
default: {

View File

@ -102,7 +102,7 @@ const Apps = (): React.ReactElement => {
)
}
const onUserTxReject = () => {
const onTxReject = () => {
sendMessageToIframe(
{ messageId: INTERFACE_MESSAGES.TRANSACTION_REJECTED, data: {} },
confirmTransactionModal.requestId,
@ -212,10 +212,9 @@ const Apps = (): React.ReactElement => {
ethBalance={ethBalance as string}
safeName={safeName as string}
txs={confirmTransactionModal.txs}
onCancel={closeConfirmationModal}
onClose={closeConfirmationModal}
onUserConfirm={onUserTxConfirm}
onUserTxReject={onUserTxReject}
onTxReject={onTxReject}
/>
</>
)