Feature: Send env info message on safe apps sdk initialization (#1349)
This commit is contained in:
parent
59dc1f711c
commit
eebe972bac
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue