Merge pull request #1796 from gnosis/release/v2.18.0

Backmerge release v2.18.0 to development
This commit is contained in:
Daniel Sanchez 2021-01-19 21:52:30 +01:00 committed by GitHub
commit 87470956fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 242 additions and 187 deletions

View File

@ -1,55 +0,0 @@
name: Build/release
# this will help you specify where to run
on:
push:
branches:
# this will run on the specified branch
- feature/desktop-app
env:
REACT_APP_BLOCKNATIVE_KEY: ${{ secrets.REACT_APP_BLOCKNATIVE_KEY }}
REACT_APP_FORTMATIC_KEY: ${{ secrets.REACT_APP_FORTMATIC_KEY }}
REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET: ${{ secrets.REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET }}
REACT_APP_INFURA_TOKEN: ${{ secrets.REACT_APP_INFURA_TOKEN }}
REACT_APP_PORTIS_ID: ${{ secrets.REACT_APP_PORTIS_ID }}
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 10.16
- name: Build/release Electron app
env:
# macOS notarization API key
APPLEID: ${{ secrets.APPLE_ID }}
APPLEIDPASS: ${{ secrets.APPLE_ID_PASS }}
uses: samuelmeuli/action-electron-builder@v1
with:
#Build scipt
build_script_name: build-desktop
# GitHub token, automatically provided to the action
# (No need to define this secret in the repo settings)
github_token: ${{ secrets.github_token }}
# macOS code signing certificate
mac_certs: ${{ secrets.MAC_CERTS }}
mac_certs_password: ${{ secrets.MAC_CERTS_PASSWORD }}
# If the commit is tagged with a version (e.g. "v1.0.0"),
# release the app after building
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

@ -5,7 +5,6 @@ on:
workflow_dispatch
env:
REACT_APP_BLOCKNATIVE_KEY: ${{ secrets.REACT_APP_BLOCKNATIVE_KEY }}
REACT_APP_FORTMATIC_KEY: ${{ secrets.REACT_APP_FORTMATIC_KEY }}
REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET: ${{ secrets.REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET }}
REACT_APP_INFURA_TOKEN: ${{ secrets.REACT_APP_INFURA_TOKEN }}
@ -21,24 +20,24 @@ jobs:
fail-fast: false
max-parallel: 15
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
os: [macos-latest, windows-latest, ubuntu-20.04]
steps:
- name: Check out Git repository
uses: actions/checkout@v2
# Add cache for yarn directory
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
# - uses: actions/cache@v2
# id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
# with:
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-yarn-
- name: Patch node gyp on windows to support Visual Studio 2019
if: startsWith(matrix.os, 'windows')
@ -52,9 +51,9 @@ jobs:
yarn global add node-gyp
yarn config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
uses: actions/setup-node@v2
with:
node-version: 12
node-version: 14
- run: yarn install --frozen-lockfile --network-concurrency 1
- name: Build/Release Desktop App
env:

View File

@ -161,7 +161,6 @@ export type GasPriceOracle = {
- **REACT_APP_GOOGLE_ANALYTICS**: Used for enabling google analytics
- **REACT_APP_PORTIS_ID**: Portis ID for enabling it on given network
- **REACT_APP_FORTMATIC_KEY**: Formatic yey for given network
- **REACT_APP_BLOCKNATIVE_KEY**: Blocknative key for given network
---
## How to add a network
@ -190,7 +189,6 @@ export enum ETHEREUM_NETWORK {
* REACT_APP_GOOGLE_ANALYTICS
* REACT_APP_PORTIS_ID
* REACT_APP_FORTMATIC_KEY
* REACT_APP_BLOCKNATIVE_KEY
3) Add the **NetworkSettings** in [`src/config/networks`](/src/config/networks) as `<network_name>.ts`:

View File

@ -1,6 +1,6 @@
{
"name": "safe-react",
"version": "2.17.0",
"version": "2.18.0",
"description": "Allowing crypto users manage funds in a safer way",
"website": "https://github.com/gnosis/safe-react#readme",
"bugs": {
@ -94,21 +94,23 @@
}
]
},
"files": [
"build/",
"files": [
"build",
"patches",
"public",
"scripts",
"dev-app-update.yml",
"package.json"
],
"directories": {
"buildResources": "public/build"
"buildResources": "public/resources"
},
"mac": {
"category": "public.app-category.productivity",
"hardenedRuntime": true,
"entitlements": "public/build/entitlements.mac.plist",
"entitlements": "public/resources/entitlements.mac.plist",
"gatekeeperAssess": false,
"entitlementsInherit": "public/build/entitlements.mac.plist",
"entitlementsInherit": "public/resources/entitlements.mac.plist",
"target": [
"dmg",
"zip"
@ -136,7 +138,7 @@
"target": [
"nsis"
],
"icon": "public/build/icon.ico"
"icon": "public/resources/icon.ico"
}
},
"resolutions": {
@ -161,7 +163,7 @@
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#bf3a84486b7353bd25447ddff39c406f6fafecc6",
"@gnosis.pm/util-contracts": "2.0.6",
"@ledgerhq/hw-transport-node-hid-singleton": "5.36.0",
"@ledgerhq/hw-transport-node-hid-singleton": "5.38.0",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.11.0",
"@material-ui/lab": "4.0.0-alpha.56",
@ -249,7 +251,7 @@
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"dotenv-expand": "^5.1.0",
"electron": "^9.3.5",
"electron": "^9.4.0",
"electron-builder": "22.9.1",
"electron-notarize": "1.0.0",
"eslint": "^7.11.0",

View File

@ -90,9 +90,10 @@ function createWindow(port = DEFAULT_PORT) {
webPreferences: {
preload: path.join(__dirname, '../scripts/preload.js'),
allowRunningInsecureContent: true,
enableRemoteModule: true,
nativeWindowOpen: true, // need to be set in order to display modal
},
icon: electron.nativeImage.createFromPath(path.join(__dirname, '/public/build/safe.png')),
icon: electron.nativeImage.createFromPath(path.join(__dirname, '../build/resources/safe.png')),
})
mainWindow.once('ready-to-show', () => {
@ -141,7 +142,7 @@ process.on('uncaughtException', function (error) {
})
app.userAgentFallback =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) old-airport-include/1.0.0 Chrome Electron/9.3.1 Safari/537.36'
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) old-airport-include/1.0.0 Chrome Electron/9.4.1 Safari/537.36'
// We have one non-context-aware module in node_modules/usb. This is used by @ledgerhq/hw-transport-node-hid
// This type of modules will be impossible to use after electron 10

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -3,6 +3,10 @@ import { EstimationStatus } from 'src/logic/hooks/useEstimateTransactionGas'
import Paragraph from 'src/components/layout/Paragraph'
import { getNetworkInfo } from 'src/config'
import { TransactionFailText } from 'src/components/TransactionFailText'
import { useSelector } from 'react-redux'
import { providerNameSelector } from 'src/logic/wallets/store/selectors'
import { sameString } from 'src/utils/strings'
import { WALLETS } from 'src/config/networks/network.d'
type TransactionFailTextProps = {
txEstimationExecutionStatus: EstimationStatus
@ -20,6 +24,8 @@ export const TransactionFees = ({
isOffChainSignature,
txEstimationExecutionStatus,
}: TransactionFailTextProps): React.ReactElement | null => {
const providerName = useSelector(providerNameSelector)
let transactionAction
if (isCreation) {
transactionAction = 'create'
@ -29,6 +35,11 @@ export const TransactionFees = ({
transactionAction = 'approve'
}
// FIXME this should be removed when estimating with WalletConnect correctly
if (!providerName || sameString(providerName, WALLETS.WALLET_CONNECT)) {
return null
}
return (
<>
<Paragraph>

View File

@ -130,7 +130,11 @@ export const estimateGasForDeployingSafe = async (
const proxyFactoryData = proxyFactoryMaster.methods
.createProxyWithNonce(safeMaster.options.address, gnosisSafeData, safeCreationSalt)
.encodeABI()
const gas = await calculateGasOf(proxyFactoryData, userAccount, proxyFactoryMaster.options.address)
const gas = await calculateGasOf({
data: proxyFactoryData,
from: userAccount,
to: proxyFactoryMaster.options.address,
})
const gasPrice = await calculateGasPrice()
return gas * parseInt(gasPrice, 10)

View File

@ -21,6 +21,8 @@ import { List } from 'immutable'
import { Confirmation } from 'src/logic/safe/store/models/types/confirmation'
import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { sameString } from 'src/utils/strings'
import { WALLETS } from 'src/config/networks/network.d'
export enum EstimationStatus {
LOADING = 'LOADING',
@ -28,13 +30,19 @@ export enum EstimationStatus {
SUCCESS = 'SUCCESS',
}
const checkIfTxIsExecution = (threshold: number, preApprovingOwner?: string, txConfirmations?: number): boolean =>
txConfirmations === threshold || !!preApprovingOwner || threshold === 1
const checkIfTxIsExecution = (
threshold: number,
preApprovingOwner?: string,
txConfirmations?: number,
txType?: string,
): boolean =>
txConfirmations === threshold || !!preApprovingOwner || threshold === 1 || sameString(txType, 'spendingLimit')
const checkIfTxIsApproveAndExecution = (threshold: number, txConfirmations: number): boolean =>
txConfirmations + 1 === threshold
const checkIfTxIsApproveAndExecution = (threshold: number, txConfirmations: number, txType?: string): boolean =>
txConfirmations + 1 === threshold || sameString(txType, 'spendingLimit')
const checkIfTxIsCreation = (txConfirmations: number): boolean => txConfirmations === 0
const checkIfTxIsCreation = (txConfirmations: number, txType?: string): boolean =>
txConfirmations === 0 && !sameString(txType, 'spendingLimit')
type TransactionEstimationProps = {
txData: string
@ -115,6 +123,7 @@ type UseEstimateTransactionGasProps = {
preApprovingOwner?: string
operation?: number
safeTxGas?: number
txType?: string
}
type TransactionGasEstimationResult = {
@ -136,6 +145,7 @@ export const useEstimateTransactionGas = ({
preApprovingOwner,
operation,
safeTxGas,
txType,
}: UseEstimateTransactionGasProps): TransactionGasEstimationResult => {
const [gasEstimation, setGasEstimation] = useState<TransactionGasEstimationResult>({
txEstimationExecutionStatus: EstimationStatus.LOADING,
@ -151,17 +161,21 @@ export const useEstimateTransactionGas = ({
const safeAddress = useSelector(safeParamAddressFromStateSelector)
const threshold = useSelector(safeThresholdSelector)
const safeVersion = useSelector(safeCurrentVersionSelector)
const { account: from, smartContractWallet } = useSelector(providerSelector)
const { account: from, smartContractWallet, name: providerName } = useSelector(providerSelector)
useEffect(() => {
const estimateGas = async () => {
if (!txData.length) {
return
}
// FIXME this should be removed when estimating with WalletConnect correctly
if (!providerName || sameString(providerName, WALLETS.WALLET_CONNECT)) {
return null
}
const isExecution = checkIfTxIsExecution(Number(threshold), preApprovingOwner, txConfirmations?.size)
const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0)
const approvalAndExecution = checkIfTxIsApproveAndExecution(Number(threshold), txConfirmations?.size || 0)
const isExecution = checkIfTxIsExecution(Number(threshold), preApprovingOwner, txConfirmations?.size, txType)
const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0, txType)
const approvalAndExecution = checkIfTxIsApproveAndExecution(Number(threshold), txConfirmations?.size || 0, txType)
try {
const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion)
@ -235,6 +249,8 @@ export const useEstimateTransactionGas = ({
safeVersion,
smartContractWallet,
safeTxGas,
txType,
providerName,
])
return gasEstimation

View File

@ -32,6 +32,7 @@ interface ProcessTransactionArgs {
safeAddress: string
tx: Transaction
userAddress: string
thresholdReached: boolean
}
type ProcessTransactionAction = ThunkAction<Promise<void | string>, AppReduxState, DispatchReturn, AnyAction>
@ -42,6 +43,7 @@ export const processTransaction = ({
safeAddress,
tx,
userAddress,
thresholdReached,
}: ProcessTransactionArgs): ProcessTransactionAction => async (
dispatch: Dispatch,
getState: () => AppReduxState,
@ -56,7 +58,7 @@ export const processTransaction = ({
const isExecution = approveAndExecute || (await shouldExecuteTransaction(safeInstance, nonce, lastTx))
const safeVersion = await getCurrentSafeVersion(safeInstance)
const preApprovingOwner = approveAndExecute ? userAddress : undefined
const preApprovingOwner = approveAndExecute && !thresholdReached ? userAddress : undefined
let sigs = generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
if (!sigs) {

View File

@ -25,6 +25,21 @@ const parseRequiredTxGasResponse = (data: string): number => {
return data.match(/.{2}/g)?.reduce(reducer, 0)
}
interface ErrorDataJson extends JSON {
originalError?: {
data?: string
}
data?: string
}
const getJSONOrNullFromString = (stringInput: string): ErrorDataJson | null => {
try {
return JSON.parse(stringInput)
} catch (error) {
return null
}
}
// Parses the result from the error message (GETH, OpenEthereum/Parity and Nethermind) and returns the data value
export const getDataFromNodeErrorMessage = (errorMessage: string): string | undefined => {
// Replace illegal characters that often comes within the error string (like <20> for example)
@ -35,7 +50,13 @@ export const getDataFromNodeErrorMessage = (errorMessage: string): string | unde
const [, ...error] = normalizedErrorString.split('\n')
try {
const errorAsJSON = JSON.parse(error.join(''))
const errorAsString = error.join('')
const errorAsJSON = getJSONOrNullFromString(errorAsString)
// Trezor wallet returns the error not as an JSON object but directly as string
if (!errorAsJSON) {
return errorAsString.length ? errorAsString : undefined
}
// For new GETH nodes they will return the data as error in the format:
// {
@ -251,5 +272,9 @@ export const estimateGasForTransactionApproval = async ({
from,
})
const approveTransactionTxData = await safeInstance.methods.approveHash(txHash).encodeABI()
return calculateGasOf(approveTransactionTxData, from, safeAddress)
return calculateGasOf({
data: approveTransactionTxData,
from,
to: safeAddress,
})
}

View File

@ -6,7 +6,6 @@ import {
SAFE_MASTER_COPY_ADDRESS,
getGnosisSafeInstanceAt,
} from 'src/logic/contracts/safeContracts'
import { DELEGATE_CALL } from 'src/logic/safe/transactions'
import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { MultiSend } from 'src/types/contracts/MultiSend.d'
@ -49,7 +48,7 @@ export const getEncodedMultiSendCallData = (txs: MultiSendTx[], web3: Web3): str
return encodedMultiSendCallData
}
export const upgradeSafeToLatestVersion = async (safeAddress: string, createTransaction): Promise<void> => {
export const getUpgradeSafeTransactionHash = async (safeAddress: string): Promise<string> => {
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
const updateSafeTxData = safeInstance.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI()
@ -69,17 +68,5 @@ export const upgradeSafeToLatestVersion = async (safeAddress: string, createTran
]
const web3 = getWeb3()
const encodeMultiSendCallData = getEncodedMultiSendCallData(txs, web3)
createTransaction({
safeAddress,
to: MULTI_SEND_ADDRESS,
valueInWei: 0,
txData: encodeMultiSendCallData,
notifiedTransaction: 'STANDARD_TX',
enqueueSnackbar: () => {},
closeSnackbar: () => {},
operation: DELEGATE_CALL,
})
return
return getEncodedMultiSendCallData(txs, web3)
}

View File

@ -50,10 +50,16 @@ export const calculateGasPrice = async (): Promise<string> => {
}
}
export const calculateGasOf = async (data: string, from: string, to: string): Promise<number> => {
export const calculateGasOf = async (txConfig: {
to: string
from: string
data: string
gasPrice?: number
gas?: number
}): Promise<number> => {
const web3 = getWeb3()
try {
const gas = await web3.eth.estimateGas({ data, from, to })
const gas = await web3.eth.estimateGas(txConfig)
return gas * 2
} catch (err) {

View File

@ -25,6 +25,8 @@ import GasEstimationInfo from './GasEstimationInfo'
import { getNetworkInfo } from 'src/config'
import { TransactionParams } from './AppFrame'
import { EstimationStatus, useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas'
import Row from 'src/components/layout/Row'
import { TransactionFees } from 'src/components/TransactionsFees'
const isTxValid = (t: Transaction): boolean => {
if (!['string', 'number'].includes(typeof t.value)) {
@ -67,6 +69,10 @@ const StyledTextBox = styled(TextBox)`
max-width: 444px;
`
const Container = styled.div`
max-width: 480px;
`
type OwnProps = {
isOpen: boolean
app: SafeApp
@ -96,7 +102,14 @@ export const ConfirmTransactionModal = ({
}: OwnProps): React.ReactElement | null => {
const [estimatedSafeTxGas, setEstimatedSafeTxGas] = useState(0)
const { gasEstimation, txEstimationExecutionStatus } = useEstimateTransactionGas({
const {
gasEstimation,
isOffChainSignature,
isCreation,
isExecution,
gasCostFormatted,
txEstimationExecutionStatus,
} = useEstimateTransactionGas({
txData: encodeMultiSendCall(txs),
txRecipient: MULTI_SEND_ADDRESS,
operation: DELEGATE_CALL,
@ -159,7 +172,7 @@ export const ConfirmTransactionModal = ({
</Text>
</>
) : (
<>
<Container>
<AddressInfo ethBalance={ethBalance} safeAddress={safeAddress} safeName={safeName} />
<DividerLine withArrow />
{txs.map((tx, index) => (
@ -195,7 +208,16 @@ export const ConfirmTransactionModal = ({
/>
</div>
)}
</>
<Row>
<TransactionFees
gasCostFormatted={gasCostFormatted}
isExecution={isExecution}
isCreation={isCreation}
isOffChainSignature={isOffChainSignature}
txEstimationExecutionStatus={txEstimationExecutionStatus}
/>
</Row>
</Container>
)
return (

View File

@ -64,7 +64,7 @@ const ReviewCollectible = ({ onClose, onPrev, tx }: Props): React.ReactElement =
isCreation,
} = useEstimateTransactionGas({
txData: data,
txRecipient: tx.recipientAddress,
txRecipient: tx.assetAddress,
})
useEffect(() => {

View File

@ -56,20 +56,6 @@ type ReviewTxProps = {
tx: ReviewTxProp
}
const useTxAmount = (tx: ReviewTxProp, isSendingNativeToken: boolean, txToken?: RecordOf<TokenProps>): string => {
const [txAmount, setTxAmount] = useState('0')
// txAmount should be 0 if we send tokens
// the real value is encoded in txData and will be used by the contract
// if txAmount > 0 it would send ETH from the Safe (and the data will be empty)
useEffect(() => {
const txAmount = isSendingNativeToken ? toTokenUnit(tx.amount, nativeCoin.decimals) : '0'
setTxAmount(txAmount)
}, [tx.amount, txToken, isSendingNativeToken])
return txAmount
}
const useTxData = (
isSendingNativeToken: boolean,
txAmount: string,
@ -88,7 +74,8 @@ const useTxData = (
if (!isSendingNativeToken) {
const StandardToken = await getHumanFriendlyToken()
const tokenInstance = await StandardToken.at(txToken.address as string)
txData = tokenInstance.contract.methods.transfer(recipientAddress, txAmount).encodeABI()
const erc20TransferAmount = toTokenUnit(txAmount, txToken.decimals)
txData = tokenInstance.contract.methods.transfer(recipientAddress, erc20TransferAmount).encodeABI()
}
setData(txData)
}
@ -107,9 +94,8 @@ const ReviewTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactElement =>
const txToken = useMemo(() => tokens.find((token) => sameAddress(token.address, tx.token)), [tokens, tx.token])
const isSendingNativeToken = sameAddress(txToken?.address, nativeCoin.address)
const txRecipient = isSendingNativeToken ? tx.recipientAddress : txToken?.address || ''
const txAmount = useTxAmount(tx, isSendingNativeToken, txToken)
const data = useTxData(isSendingNativeToken, txAmount, tx.recipientAddress, txToken)
const txValue = isSendingNativeToken ? toTokenUnit(tx.amount, nativeCoin.decimals) : '0'
const data = useTxData(isSendingNativeToken, tx.amount, tx.recipientAddress, txToken)
const {
gasCostFormatted,
@ -120,6 +106,7 @@ const ReviewTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactElement =>
} = useEstimateTransactionGas({
txData: data,
txRecipient,
txType: tx.txType,
})
const submitTx = async () => {
@ -152,7 +139,7 @@ const ReviewTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactElement =>
createTransaction({
safeAddress: safeAddress,
to: txRecipient as string,
valueInWei: txAmount,
valueInWei: txValue,
txData: data,
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
}),

View File

@ -19,7 +19,7 @@ import enqueueSnackbar from 'src/logic/notifications/store/actions/enqueueSnackb
import { getNotificationsFromTxType, enhanceSnackbarForAction } from 'src/logic/notifications'
import { sameAddress } from 'src/logic/wallets/ethAddresses'
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import UpdateSafeModal from 'src/routes/safe/components/Settings/UpdateSafeModal'
import { UpdateSafeModal } from 'src/routes/safe/components/Settings/UpdateSafeModal'
import { grantedSelector } from 'src/routes/safe/container/selector'
import updateSafe from 'src/logic/safe/store/actions/updateSafe'
import Link from 'src/components/layout/Link'

View File

@ -1,9 +1,7 @@
import IconButton from '@material-ui/core/IconButton'
import Close from '@material-ui/icons/Close'
import { withStyles } from '@material-ui/styles'
import React from 'react'
import React, { useEffect, useState } from 'react'
import { useDispatch } from 'react-redux'
import { bindActionCreators } from 'redux'
import { styles } from './style'
@ -13,17 +11,61 @@ import Button from 'src/components/layout/Button'
import Hairline from 'src/components/layout/Hairline'
import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row'
import { upgradeSafeToLatestVersion } from 'src/logic/safe/utils/upgradeSafe'
import { getUpgradeSafeTransactionHash } from 'src/logic/safe/utils/upgradeSafe'
import createTransaction from 'src/logic/safe/store/actions/createTransaction'
import { makeStyles } from '@material-ui/core'
import { TransactionFees } from 'src/components/TransactionsFees'
import { useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas'
import { MULTI_SEND_ADDRESS } from 'src/logic/contracts/safeContracts'
import { DELEGATE_CALL } from 'src/logic/safe/transactions'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
const UpdateSafeModal = ({ classes, onClose, safeAddress }) => {
const useStyles = makeStyles(styles)
type Props = {
onClose: () => void
safeAddress: string
}
export const UpdateSafeModal = ({ onClose, safeAddress }: Props): React.ReactElement => {
const classes = useStyles()
const dispatch = useDispatch()
const [multiSendCallData, setMultiSendCallData] = useState(EMPTY_DATA)
useEffect(() => {
const calculateUpgradeSafeModal = async () => {
const encodeMultiSendCallData = await getUpgradeSafeTransactionHash(safeAddress)
setMultiSendCallData(encodeMultiSendCallData)
}
calculateUpgradeSafeModal()
}, [safeAddress])
const handleSubmit = async () => {
// Call the update safe method
await upgradeSafeToLatestVersion(safeAddress, bindActionCreators(createTransaction, dispatch))
dispatch(
createTransaction({
safeAddress,
to: MULTI_SEND_ADDRESS,
valueInWei: '0',
txData: multiSendCallData,
notifiedTransaction: 'STANDARD_TX',
operation: DELEGATE_CALL,
}),
)
onClose()
}
const {
gasCostFormatted,
txEstimationExecutionStatus,
isExecution,
isCreation,
isOffChainSignature,
} = useEstimateTransactionGas({
txData: multiSendCallData,
txRecipient: safeAddress,
})
return (
<>
<Row align="center" className={classes.heading} grow>
@ -56,6 +98,15 @@ const UpdateSafeModal = ({ classes, onClose, safeAddress }) => {
have to confirm the update in case more than one confirmation is required for this Safe.
</Paragraph>
</Row>
<Row>
<TransactionFees
gasCostFormatted={gasCostFormatted}
isExecution={isExecution}
isCreation={isCreation}
isOffChainSignature={isOffChainSignature}
txEstimationExecutionStatus={txEstimationExecutionStatus}
/>
</Row>
</Block>
<Hairline style={{ position: 'absolute', bottom: 85 }} />
<Row align="center" className={classes.buttonRow}>
@ -72,5 +123,3 @@ const UpdateSafeModal = ({ classes, onClose, safeAddress }) => {
</>
)
}
export default withStyles(styles as any)(UpdateSafeModal)

View File

@ -1,6 +1,7 @@
import { lg, md, secondaryText, sm } from 'src/theme/variables'
import { createStyles } from '@material-ui/core'
export const styles = () => ({
export const styles = createStyles({
heading: {
padding: `${sm} ${lg}`,
justifyContent: 'space-between',

View File

@ -105,6 +105,7 @@ export const ApproveTxModal = ({
userAddress,
notifiedTransaction: TX_NOTIFICATION_TYPES.CONFIRMATION_TX,
approveAndExecute: canExecute && approveAndExecute && isTheTxReadyToBeExecuted,
thresholdReached,
}),
)
onClose()

View File

@ -7,7 +7,6 @@ export const GOOGLE_ANALYTICS_ID = process.env.REACT_APP_GOOGLE_ANALYTICS || ''
export const SENTRY_DSN = process.env.REACT_APP_SENTRY_DSN || ''
export const PORTIS_ID = process.env.REACT_APP_PORTIS_ID ?? '852b763d-f28b-4463-80cb-846d7ec5806b'
export const FORTMATIC_KEY = process.env.REACT_APP_FORTMATIC_KEY ?? 'pk_test_CAD437AA29BE0A40'
export const BLOCKNATIVE_KEY = process.env.REACT_APP_BLOCKNATIVE_KEY ?? '7fbb9cee-7e97-4436-8770-8b29a9a8814c'
/*
* Not being used
export const SQUARELINK_ID = {

View File

@ -1782,19 +1782,19 @@
dependencies:
invariant "2"
"@ledgerhq/devices@^5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.36.0.tgz#f4493bea44390325fcc7a2a0d03bba69fc1604ec"
integrity sha512-EwQwLZcz66a2V07Bad0J+Q67LR2afj2NJChJNcA6/gqvzXrtNtJ37u1co9eLU7S5GGll5JGi7KdBqAD9ZTHaaQ==
"@ledgerhq/devices@^5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.38.0.tgz#0b805020c4f3ac40d35f1b1af6d64d04256b1e0f"
integrity sha512-1RZ+Dh+oVUDMeaPSCeQ56qzgiMHHy481dbkRCDUMRJEzkGqOLI3k34x7XdkVKy1NQdt8G8sYyobP/yixDry5ow==
dependencies:
"@ledgerhq/errors" "^5.36.0"
"@ledgerhq/logs" "^5.36.0"
"@ledgerhq/errors" "^5.38.0"
"@ledgerhq/logs" "^5.38.0"
rxjs "^6.6.3"
"@ledgerhq/errors@^5.34.0", "@ledgerhq/errors@^5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.36.0.tgz#9d178b54116ae81b1fbdfa80afcd33981453be4c"
integrity sha512-VS6aFzn3IDUmSLaX2kAPg5sQOc5m7IwvswAGvoMc3FCi9/a1dXWwtiYn5rWd1QjDJlTKSfCwmSpvUMp8FKoY2Q==
"@ledgerhq/errors@^5.34.0", "@ledgerhq/errors@^5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.38.0.tgz#1642b87de47cbabc7b75ca93005a690895920a72"
integrity sha512-d4gQzbOLNBoGIwDtEGFNSb0w0aYN10T5Y749e+vqiJoS3dWrB+5BCSQ/U/ALet0wi/UMIyFY/xmgd1gPaPB3Hw==
"@ledgerhq/hw-app-eth@^5.21.0":
version "5.37.0"
@ -1807,27 +1807,27 @@
bignumber.js "^9.0.1"
rlp "^2.2.6"
"@ledgerhq/hw-transport-node-hid-noevents@^5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.36.0.tgz#a25bdf0d10f9eac73148040e5887f40ca46f6a93"
integrity sha512-8zwokin0KFJaTzhy7oLVcy4QCNUjMuc49wPLnr3zxLqhO1innMp2crUxjIFNLRGJm/TfDLnlpxTPud6WZoo5zg==
"@ledgerhq/hw-transport-node-hid-noevents@^5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.38.0.tgz#ffbfb0b997e585fc08b6b220997caaa59e094554"
integrity sha512-zuxN3gWfCuN+pbK3BKc8z3VCulKI7zee1N3xhCWua9TiwL3leBTBs25Bvm22fmiLJYhzszccbF673/bpnnIQAA==
dependencies:
"@ledgerhq/devices" "^5.36.0"
"@ledgerhq/errors" "^5.36.0"
"@ledgerhq/hw-transport" "^5.36.0"
"@ledgerhq/logs" "^5.36.0"
"@ledgerhq/devices" "^5.38.0"
"@ledgerhq/errors" "^5.38.0"
"@ledgerhq/hw-transport" "^5.38.0"
"@ledgerhq/logs" "^5.38.0"
node-hid "2.1.1"
"@ledgerhq/hw-transport-node-hid-singleton@5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-singleton/-/hw-transport-node-hid-singleton-5.36.0.tgz#99cedb773e571642d7f151c3134c5924147bc0d8"
integrity sha512-eKkJGXW0m7PeJY7V/7FDfU4VFLIVSRjxi7PpfJKFYlUrRwx9QndlZT0LD0u3W9dLktgounHhsOuXvuG44uTHYA==
"@ledgerhq/hw-transport-node-hid-singleton@5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-singleton/-/hw-transport-node-hid-singleton-5.38.0.tgz#ea133ac3a7015aaafd5d629388da4d4a2086c761"
integrity sha512-FPpr6R2Cs6YKCamprC9vzJa+P7RieyMLQC3cG6EjYg8tmvHPtIxpmWFclNi45jZ05Ve1YvNjutoHVTVn0cOnpg==
dependencies:
"@ledgerhq/devices" "^5.36.0"
"@ledgerhq/errors" "^5.36.0"
"@ledgerhq/hw-transport" "^5.36.0"
"@ledgerhq/hw-transport-node-hid-noevents" "^5.36.0"
"@ledgerhq/logs" "^5.36.0"
"@ledgerhq/devices" "^5.38.0"
"@ledgerhq/errors" "^5.38.0"
"@ledgerhq/hw-transport" "^5.38.0"
"@ledgerhq/hw-transport-node-hid-noevents" "^5.38.0"
"@ledgerhq/logs" "^5.38.0"
lodash "^4.17.20"
node-hid "2.1.1"
usb-detection "^4.10.0"
@ -1842,19 +1842,19 @@
"@ledgerhq/logs" "^5.30.0"
u2f-api "0.2.7"
"@ledgerhq/hw-transport@^5.34.0", "@ledgerhq/hw-transport@^5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.36.0.tgz#b6e951c411182ece59c7b527f948240d1b0a8a51"
integrity sha512-rwLTBUsdGCC3Ka4G99sqGbbyVhkVxXd4eWWeOb8gnuKhrTydZGkkP3JdZSHgWSrVRYTAUmkE1AnUmchbfh361w==
"@ledgerhq/hw-transport@^5.34.0", "@ledgerhq/hw-transport@^5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.38.0.tgz#b02bea73d77e729d13c367a967df1666f9ef940d"
integrity sha512-CAxvHukCcp+RqaEsSltmBw4Lb1yW42fiF/LTYN7JvCkZyLIQhvkndLDVCgp4hpMdtLK4bkf7RJRElqbN0vRoAQ==
dependencies:
"@ledgerhq/devices" "^5.36.0"
"@ledgerhq/errors" "^5.36.0"
"@ledgerhq/devices" "^5.38.0"
"@ledgerhq/errors" "^5.38.0"
events "^3.2.0"
"@ledgerhq/logs@^5.30.0", "@ledgerhq/logs@^5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.36.0.tgz#78721347162fb834d90effa1123b363dc46e3a52"
integrity sha512-HnD/hByteUL1MsJu1lMinY9bNq8++5mWJ8qHCW9dLC9LbsvWIqwLwmZiGcW0D2tX9p0/C5ESuIpJ9B/d2dReuw==
"@ledgerhq/logs@^5.30.0", "@ledgerhq/logs@^5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.38.0.tgz#3c5dbd1f62c0bf5580477b218fb57c67b575643a"
integrity sha512-i87Yn89Cq2D9Y0KmrEzCm62XHzI2edeOTBENKH6vAyzESGzyF+SBoqtZNwrjJcKup3/9dNn/zHjpicY7ev94Vw==
"@material-ui/core@^4.11.0":
version "4.11.2"
@ -8156,10 +8156,10 @@ electron-updater@4.3.5:
lodash.isequal "^4.5.0"
semver "^7.3.2"
electron@^9.3.5:
version "9.3.5"
resolved "https://registry.yarnpkg.com/electron/-/electron-9.3.5.tgz#7967146b81e6d9b484773243fd4a4f671a50b884"
integrity sha512-EPmDsp7sO0UPtw7nLD1ufse/nBskP+ifXzBgUg9psCUlapkzuwYi6pmLAzKLW/bVjwgyUKwh1OKWILWfOeLGcQ==
electron@^9.4.0:
version "9.4.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-9.4.1.tgz#62a2aae4cd93f1b56d794a47541505a71654177a"
integrity sha512-r4CxoVG9Ja7tBtkilWMnBsBGup8G8Z+v7icZmwysHa8/OSr0OrLjrcOF/30BAP7yPE5fz/XTxygnltzW4OTZdw==
dependencies:
"@electron/get" "^1.0.1"
"@types/node" "^12.0.12"