Merge pull request #1796 from gnosis/release/v2.18.0
Backmerge release v2.18.0 to development
This commit is contained in:
commit
87470956fc
|
@ -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') }}
|
|
|
@ -5,7 +5,6 @@ on:
|
||||||
workflow_dispatch
|
workflow_dispatch
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REACT_APP_BLOCKNATIVE_KEY: ${{ secrets.REACT_APP_BLOCKNATIVE_KEY }}
|
|
||||||
REACT_APP_FORTMATIC_KEY: ${{ secrets.REACT_APP_FORTMATIC_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_GOOGLE_ANALYTICS_ID_MAINNET: ${{ secrets.REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET }}
|
||||||
REACT_APP_INFURA_TOKEN: ${{ secrets.REACT_APP_INFURA_TOKEN }}
|
REACT_APP_INFURA_TOKEN: ${{ secrets.REACT_APP_INFURA_TOKEN }}
|
||||||
|
@ -21,24 +20,24 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
max-parallel: 15
|
max-parallel: 15
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
os: [macos-latest, windows-latest, ubuntu-20.04]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
# Add cache for yarn directory
|
# Add cache for yarn directory
|
||||||
- name: Get yarn cache directory path
|
# - name: Get yarn cache directory path
|
||||||
id: yarn-cache-dir-path
|
# id: yarn-cache-dir-path
|
||||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
# run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
# - uses: actions/cache@v2
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
# id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
# with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
restore-keys: |
|
# restore-keys: |
|
||||||
${{ runner.os }}-yarn-
|
# ${{ runner.os }}-yarn-
|
||||||
|
|
||||||
- name: Patch node gyp on windows to support Visual Studio 2019
|
- name: Patch node gyp on windows to support Visual Studio 2019
|
||||||
if: startsWith(matrix.os, 'windows')
|
if: startsWith(matrix.os, 'windows')
|
||||||
|
@ -52,9 +51,9 @@ jobs:
|
||||||
yarn global add node-gyp
|
yarn global add node-gyp
|
||||||
yarn config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"
|
yarn config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Install Node.js, NPM and Yarn
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
- run: yarn install --frozen-lockfile --network-concurrency 1
|
- run: yarn install --frozen-lockfile --network-concurrency 1
|
||||||
- name: Build/Release Desktop App
|
- name: Build/Release Desktop App
|
||||||
env:
|
env:
|
||||||
|
|
|
@ -161,7 +161,6 @@ export type GasPriceOracle = {
|
||||||
- **REACT_APP_GOOGLE_ANALYTICS**: Used for enabling google analytics
|
- **REACT_APP_GOOGLE_ANALYTICS**: Used for enabling google analytics
|
||||||
- **REACT_APP_PORTIS_ID**: Portis ID for enabling it on given network
|
- **REACT_APP_PORTIS_ID**: Portis ID for enabling it on given network
|
||||||
- **REACT_APP_FORTMATIC_KEY**: Formatic yey for 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
|
## How to add a network
|
||||||
|
@ -190,7 +189,6 @@ export enum ETHEREUM_NETWORK {
|
||||||
* REACT_APP_GOOGLE_ANALYTICS
|
* REACT_APP_GOOGLE_ANALYTICS
|
||||||
* REACT_APP_PORTIS_ID
|
* REACT_APP_PORTIS_ID
|
||||||
* REACT_APP_FORTMATIC_KEY
|
* REACT_APP_FORTMATIC_KEY
|
||||||
* REACT_APP_BLOCKNATIVE_KEY
|
|
||||||
|
|
||||||
3) Add the **NetworkSettings** in [`src/config/networks`](/src/config/networks) as `<network_name>.ts`:
|
3) Add the **NetworkSettings** in [`src/config/networks`](/src/config/networks) as `<network_name>.ts`:
|
||||||
|
|
||||||
|
|
18
package.json
18
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "safe-react",
|
"name": "safe-react",
|
||||||
"version": "2.17.0",
|
"version": "2.18.0",
|
||||||
"description": "Allowing crypto users manage funds in a safer way",
|
"description": "Allowing crypto users manage funds in a safer way",
|
||||||
"website": "https://github.com/gnosis/safe-react#readme",
|
"website": "https://github.com/gnosis/safe-react#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
@ -95,20 +95,22 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"build/",
|
"build",
|
||||||
|
"patches",
|
||||||
"public",
|
"public",
|
||||||
"scripts",
|
"scripts",
|
||||||
|
"dev-app-update.yml",
|
||||||
"package.json"
|
"package.json"
|
||||||
],
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
"buildResources": "public/build"
|
"buildResources": "public/resources"
|
||||||
},
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
"category": "public.app-category.productivity",
|
"category": "public.app-category.productivity",
|
||||||
"hardenedRuntime": true,
|
"hardenedRuntime": true,
|
||||||
"entitlements": "public/build/entitlements.mac.plist",
|
"entitlements": "public/resources/entitlements.mac.plist",
|
||||||
"gatekeeperAssess": false,
|
"gatekeeperAssess": false,
|
||||||
"entitlementsInherit": "public/build/entitlements.mac.plist",
|
"entitlementsInherit": "public/resources/entitlements.mac.plist",
|
||||||
"target": [
|
"target": [
|
||||||
"dmg",
|
"dmg",
|
||||||
"zip"
|
"zip"
|
||||||
|
@ -136,7 +138,7 @@
|
||||||
"target": [
|
"target": [
|
||||||
"nsis"
|
"nsis"
|
||||||
],
|
],
|
||||||
"icon": "public/build/icon.ico"
|
"icon": "public/resources/icon.ico"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@ -161,7 +163,7 @@
|
||||||
"@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#bf3a84486b7353bd25447ddff39c406f6fafecc6",
|
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#bf3a84486b7353bd25447ddff39c406f6fafecc6",
|
||||||
"@gnosis.pm/util-contracts": "2.0.6",
|
"@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/core": "^4.11.0",
|
||||||
"@material-ui/icons": "^4.11.0",
|
"@material-ui/icons": "^4.11.0",
|
||||||
"@material-ui/lab": "4.0.0-alpha.56",
|
"@material-ui/lab": "4.0.0-alpha.56",
|
||||||
|
@ -249,7 +251,7 @@
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"dotenv-expand": "^5.1.0",
|
"dotenv-expand": "^5.1.0",
|
||||||
"electron": "^9.3.5",
|
"electron": "^9.4.0",
|
||||||
"electron-builder": "22.9.1",
|
"electron-builder": "22.9.1",
|
||||||
"electron-notarize": "1.0.0",
|
"electron-notarize": "1.0.0",
|
||||||
"eslint": "^7.11.0",
|
"eslint": "^7.11.0",
|
||||||
|
|
|
@ -90,9 +90,10 @@ function createWindow(port = DEFAULT_PORT) {
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, '../scripts/preload.js'),
|
preload: path.join(__dirname, '../scripts/preload.js'),
|
||||||
allowRunningInsecureContent: true,
|
allowRunningInsecureContent: true,
|
||||||
|
enableRemoteModule: true,
|
||||||
nativeWindowOpen: true, // need to be set in order to display modal
|
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', () => {
|
mainWindow.once('ready-to-show', () => {
|
||||||
|
@ -141,7 +142,7 @@ process.on('uncaughtException', function (error) {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.userAgentFallback =
|
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
|
// 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
|
// This type of modules will be impossible to use after electron 10
|
||||||
|
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
@ -3,6 +3,10 @@ import { EstimationStatus } from 'src/logic/hooks/useEstimateTransactionGas'
|
||||||
import Paragraph from 'src/components/layout/Paragraph'
|
import Paragraph from 'src/components/layout/Paragraph'
|
||||||
import { getNetworkInfo } from 'src/config'
|
import { getNetworkInfo } from 'src/config'
|
||||||
import { TransactionFailText } from 'src/components/TransactionFailText'
|
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 = {
|
type TransactionFailTextProps = {
|
||||||
txEstimationExecutionStatus: EstimationStatus
|
txEstimationExecutionStatus: EstimationStatus
|
||||||
|
@ -20,6 +24,8 @@ export const TransactionFees = ({
|
||||||
isOffChainSignature,
|
isOffChainSignature,
|
||||||
txEstimationExecutionStatus,
|
txEstimationExecutionStatus,
|
||||||
}: TransactionFailTextProps): React.ReactElement | null => {
|
}: TransactionFailTextProps): React.ReactElement | null => {
|
||||||
|
const providerName = useSelector(providerNameSelector)
|
||||||
|
|
||||||
let transactionAction
|
let transactionAction
|
||||||
if (isCreation) {
|
if (isCreation) {
|
||||||
transactionAction = 'create'
|
transactionAction = 'create'
|
||||||
|
@ -29,6 +35,11 @@ export const TransactionFees = ({
|
||||||
transactionAction = 'approve'
|
transactionAction = 'approve'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME this should be removed when estimating with WalletConnect correctly
|
||||||
|
if (!providerName || sameString(providerName, WALLETS.WALLET_CONNECT)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
|
|
|
@ -130,7 +130,11 @@ export const estimateGasForDeployingSafe = async (
|
||||||
const proxyFactoryData = proxyFactoryMaster.methods
|
const proxyFactoryData = proxyFactoryMaster.methods
|
||||||
.createProxyWithNonce(safeMaster.options.address, gnosisSafeData, safeCreationSalt)
|
.createProxyWithNonce(safeMaster.options.address, gnosisSafeData, safeCreationSalt)
|
||||||
.encodeABI()
|
.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()
|
const gasPrice = await calculateGasPrice()
|
||||||
|
|
||||||
return gas * parseInt(gasPrice, 10)
|
return gas * parseInt(gasPrice, 10)
|
||||||
|
|
|
@ -21,6 +21,8 @@ import { List } from 'immutable'
|
||||||
import { Confirmation } from 'src/logic/safe/store/models/types/confirmation'
|
import { Confirmation } from 'src/logic/safe/store/models/types/confirmation'
|
||||||
import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner'
|
import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner'
|
||||||
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
|
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 {
|
export enum EstimationStatus {
|
||||||
LOADING = 'LOADING',
|
LOADING = 'LOADING',
|
||||||
|
@ -28,13 +30,19 @@ export enum EstimationStatus {
|
||||||
SUCCESS = 'SUCCESS',
|
SUCCESS = 'SUCCESS',
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkIfTxIsExecution = (threshold: number, preApprovingOwner?: string, txConfirmations?: number): boolean =>
|
const checkIfTxIsExecution = (
|
||||||
txConfirmations === threshold || !!preApprovingOwner || threshold === 1
|
threshold: number,
|
||||||
|
preApprovingOwner?: string,
|
||||||
|
txConfirmations?: number,
|
||||||
|
txType?: string,
|
||||||
|
): boolean =>
|
||||||
|
txConfirmations === threshold || !!preApprovingOwner || threshold === 1 || sameString(txType, 'spendingLimit')
|
||||||
|
|
||||||
const checkIfTxIsApproveAndExecution = (threshold: number, txConfirmations: number): boolean =>
|
const checkIfTxIsApproveAndExecution = (threshold: number, txConfirmations: number, txType?: string): boolean =>
|
||||||
txConfirmations + 1 === threshold
|
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 = {
|
type TransactionEstimationProps = {
|
||||||
txData: string
|
txData: string
|
||||||
|
@ -115,6 +123,7 @@ type UseEstimateTransactionGasProps = {
|
||||||
preApprovingOwner?: string
|
preApprovingOwner?: string
|
||||||
operation?: number
|
operation?: number
|
||||||
safeTxGas?: number
|
safeTxGas?: number
|
||||||
|
txType?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransactionGasEstimationResult = {
|
type TransactionGasEstimationResult = {
|
||||||
|
@ -136,6 +145,7 @@ export const useEstimateTransactionGas = ({
|
||||||
preApprovingOwner,
|
preApprovingOwner,
|
||||||
operation,
|
operation,
|
||||||
safeTxGas,
|
safeTxGas,
|
||||||
|
txType,
|
||||||
}: UseEstimateTransactionGasProps): TransactionGasEstimationResult => {
|
}: UseEstimateTransactionGasProps): TransactionGasEstimationResult => {
|
||||||
const [gasEstimation, setGasEstimation] = useState<TransactionGasEstimationResult>({
|
const [gasEstimation, setGasEstimation] = useState<TransactionGasEstimationResult>({
|
||||||
txEstimationExecutionStatus: EstimationStatus.LOADING,
|
txEstimationExecutionStatus: EstimationStatus.LOADING,
|
||||||
|
@ -151,17 +161,21 @@ export const useEstimateTransactionGas = ({
|
||||||
const safeAddress = useSelector(safeParamAddressFromStateSelector)
|
const safeAddress = useSelector(safeParamAddressFromStateSelector)
|
||||||
const threshold = useSelector(safeThresholdSelector)
|
const threshold = useSelector(safeThresholdSelector)
|
||||||
const safeVersion = useSelector(safeCurrentVersionSelector)
|
const safeVersion = useSelector(safeCurrentVersionSelector)
|
||||||
const { account: from, smartContractWallet } = useSelector(providerSelector)
|
const { account: from, smartContractWallet, name: providerName } = useSelector(providerSelector)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const estimateGas = async () => {
|
const estimateGas = async () => {
|
||||||
if (!txData.length) {
|
if (!txData.length) {
|
||||||
return
|
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 isExecution = checkIfTxIsExecution(Number(threshold), preApprovingOwner, txConfirmations?.size, txType)
|
||||||
const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0)
|
const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0, txType)
|
||||||
const approvalAndExecution = checkIfTxIsApproveAndExecution(Number(threshold), txConfirmations?.size || 0)
|
const approvalAndExecution = checkIfTxIsApproveAndExecution(Number(threshold), txConfirmations?.size || 0, txType)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion)
|
const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion)
|
||||||
|
@ -235,6 +249,8 @@ export const useEstimateTransactionGas = ({
|
||||||
safeVersion,
|
safeVersion,
|
||||||
smartContractWallet,
|
smartContractWallet,
|
||||||
safeTxGas,
|
safeTxGas,
|
||||||
|
txType,
|
||||||
|
providerName,
|
||||||
])
|
])
|
||||||
|
|
||||||
return gasEstimation
|
return gasEstimation
|
||||||
|
|
|
@ -32,6 +32,7 @@ interface ProcessTransactionArgs {
|
||||||
safeAddress: string
|
safeAddress: string
|
||||||
tx: Transaction
|
tx: Transaction
|
||||||
userAddress: string
|
userAddress: string
|
||||||
|
thresholdReached: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessTransactionAction = ThunkAction<Promise<void | string>, AppReduxState, DispatchReturn, AnyAction>
|
type ProcessTransactionAction = ThunkAction<Promise<void | string>, AppReduxState, DispatchReturn, AnyAction>
|
||||||
|
@ -42,6 +43,7 @@ export const processTransaction = ({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
tx,
|
tx,
|
||||||
userAddress,
|
userAddress,
|
||||||
|
thresholdReached,
|
||||||
}: ProcessTransactionArgs): ProcessTransactionAction => async (
|
}: ProcessTransactionArgs): ProcessTransactionAction => async (
|
||||||
dispatch: Dispatch,
|
dispatch: Dispatch,
|
||||||
getState: () => AppReduxState,
|
getState: () => AppReduxState,
|
||||||
|
@ -56,7 +58,7 @@ export const processTransaction = ({
|
||||||
const isExecution = approveAndExecute || (await shouldExecuteTransaction(safeInstance, nonce, lastTx))
|
const isExecution = approveAndExecute || (await shouldExecuteTransaction(safeInstance, nonce, lastTx))
|
||||||
const safeVersion = await getCurrentSafeVersion(safeInstance)
|
const safeVersion = await getCurrentSafeVersion(safeInstance)
|
||||||
|
|
||||||
const preApprovingOwner = approveAndExecute ? userAddress : undefined
|
const preApprovingOwner = approveAndExecute && !thresholdReached ? userAddress : undefined
|
||||||
let sigs = generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
|
let sigs = generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
|
||||||
|
|
||||||
if (!sigs) {
|
if (!sigs) {
|
||||||
|
|
Binary file not shown.
|
@ -25,6 +25,21 @@ const parseRequiredTxGasResponse = (data: string): number => {
|
||||||
return data.match(/.{2}/g)?.reduce(reducer, 0)
|
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
|
// Parses the result from the error message (GETH, OpenEthereum/Parity and Nethermind) and returns the data value
|
||||||
export const getDataFromNodeErrorMessage = (errorMessage: string): string | undefined => {
|
export const getDataFromNodeErrorMessage = (errorMessage: string): string | undefined => {
|
||||||
// Replace illegal characters that often comes within the error string (like <20> for example)
|
// 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')
|
const [, ...error] = normalizedErrorString.split('\n')
|
||||||
|
|
||||||
try {
|
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:
|
// For new GETH nodes they will return the data as error in the format:
|
||||||
// {
|
// {
|
||||||
|
@ -251,5 +272,9 @@ export const estimateGasForTransactionApproval = async ({
|
||||||
from,
|
from,
|
||||||
})
|
})
|
||||||
const approveTransactionTxData = await safeInstance.methods.approveHash(txHash).encodeABI()
|
const approveTransactionTxData = await safeInstance.methods.approveHash(txHash).encodeABI()
|
||||||
return calculateGasOf(approveTransactionTxData, from, safeAddress)
|
return calculateGasOf({
|
||||||
|
data: approveTransactionTxData,
|
||||||
|
from,
|
||||||
|
to: safeAddress,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
SAFE_MASTER_COPY_ADDRESS,
|
SAFE_MASTER_COPY_ADDRESS,
|
||||||
getGnosisSafeInstanceAt,
|
getGnosisSafeInstanceAt,
|
||||||
} from 'src/logic/contracts/safeContracts'
|
} from 'src/logic/contracts/safeContracts'
|
||||||
import { DELEGATE_CALL } from 'src/logic/safe/transactions'
|
|
||||||
import { getWeb3 } from 'src/logic/wallets/getWeb3'
|
import { getWeb3 } from 'src/logic/wallets/getWeb3'
|
||||||
import { MultiSend } from 'src/types/contracts/MultiSend.d'
|
import { MultiSend } from 'src/types/contracts/MultiSend.d'
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ export const getEncodedMultiSendCallData = (txs: MultiSendTx[], web3: Web3): str
|
||||||
return encodedMultiSendCallData
|
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 safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
|
const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
|
||||||
const updateSafeTxData = safeInstance.methods.changeMasterCopy(SAFE_MASTER_COPY_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 web3 = getWeb3()
|
||||||
const encodeMultiSendCallData = getEncodedMultiSendCallData(txs, web3)
|
return getEncodedMultiSendCallData(txs, web3)
|
||||||
createTransaction({
|
|
||||||
safeAddress,
|
|
||||||
to: MULTI_SEND_ADDRESS,
|
|
||||||
valueInWei: 0,
|
|
||||||
txData: encodeMultiSendCallData,
|
|
||||||
notifiedTransaction: 'STANDARD_TX',
|
|
||||||
enqueueSnackbar: () => {},
|
|
||||||
closeSnackbar: () => {},
|
|
||||||
operation: DELEGATE_CALL,
|
|
||||||
})
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
const web3 = getWeb3()
|
||||||
try {
|
try {
|
||||||
const gas = await web3.eth.estimateGas({ data, from, to })
|
const gas = await web3.eth.estimateGas(txConfig)
|
||||||
|
|
||||||
return gas * 2
|
return gas * 2
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -25,6 +25,8 @@ import GasEstimationInfo from './GasEstimationInfo'
|
||||||
import { getNetworkInfo } from 'src/config'
|
import { getNetworkInfo } from 'src/config'
|
||||||
import { TransactionParams } from './AppFrame'
|
import { TransactionParams } from './AppFrame'
|
||||||
import { EstimationStatus, useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas'
|
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 => {
|
const isTxValid = (t: Transaction): boolean => {
|
||||||
if (!['string', 'number'].includes(typeof t.value)) {
|
if (!['string', 'number'].includes(typeof t.value)) {
|
||||||
|
@ -67,6 +69,10 @@ const StyledTextBox = styled(TextBox)`
|
||||||
max-width: 444px;
|
max-width: 444px;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
max-width: 480px;
|
||||||
|
`
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
app: SafeApp
|
app: SafeApp
|
||||||
|
@ -96,7 +102,14 @@ export const ConfirmTransactionModal = ({
|
||||||
}: OwnProps): React.ReactElement | null => {
|
}: OwnProps): React.ReactElement | null => {
|
||||||
const [estimatedSafeTxGas, setEstimatedSafeTxGas] = useState(0)
|
const [estimatedSafeTxGas, setEstimatedSafeTxGas] = useState(0)
|
||||||
|
|
||||||
const { gasEstimation, txEstimationExecutionStatus } = useEstimateTransactionGas({
|
const {
|
||||||
|
gasEstimation,
|
||||||
|
isOffChainSignature,
|
||||||
|
isCreation,
|
||||||
|
isExecution,
|
||||||
|
gasCostFormatted,
|
||||||
|
txEstimationExecutionStatus,
|
||||||
|
} = useEstimateTransactionGas({
|
||||||
txData: encodeMultiSendCall(txs),
|
txData: encodeMultiSendCall(txs),
|
||||||
txRecipient: MULTI_SEND_ADDRESS,
|
txRecipient: MULTI_SEND_ADDRESS,
|
||||||
operation: DELEGATE_CALL,
|
operation: DELEGATE_CALL,
|
||||||
|
@ -159,7 +172,7 @@ export const ConfirmTransactionModal = ({
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<Container>
|
||||||
<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) => (
|
||||||
|
@ -195,7 +208,16 @@ export const ConfirmTransactionModal = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
<Row>
|
||||||
|
<TransactionFees
|
||||||
|
gasCostFormatted={gasCostFormatted}
|
||||||
|
isExecution={isExecution}
|
||||||
|
isCreation={isCreation}
|
||||||
|
isOffChainSignature={isOffChainSignature}
|
||||||
|
txEstimationExecutionStatus={txEstimationExecutionStatus}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
</Container>
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -64,7 +64,7 @@ const ReviewCollectible = ({ onClose, onPrev, tx }: Props): React.ReactElement =
|
||||||
isCreation,
|
isCreation,
|
||||||
} = useEstimateTransactionGas({
|
} = useEstimateTransactionGas({
|
||||||
txData: data,
|
txData: data,
|
||||||
txRecipient: tx.recipientAddress,
|
txRecipient: tx.assetAddress,
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -56,20 +56,6 @@ type ReviewTxProps = {
|
||||||
tx: ReviewTxProp
|
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 = (
|
const useTxData = (
|
||||||
isSendingNativeToken: boolean,
|
isSendingNativeToken: boolean,
|
||||||
txAmount: string,
|
txAmount: string,
|
||||||
|
@ -88,7 +74,8 @@ const useTxData = (
|
||||||
if (!isSendingNativeToken) {
|
if (!isSendingNativeToken) {
|
||||||
const StandardToken = await getHumanFriendlyToken()
|
const StandardToken = await getHumanFriendlyToken()
|
||||||
const tokenInstance = await StandardToken.at(txToken.address as string)
|
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)
|
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 txToken = useMemo(() => tokens.find((token) => sameAddress(token.address, tx.token)), [tokens, tx.token])
|
||||||
const isSendingNativeToken = sameAddress(txToken?.address, nativeCoin.address)
|
const isSendingNativeToken = sameAddress(txToken?.address, nativeCoin.address)
|
||||||
const txRecipient = isSendingNativeToken ? tx.recipientAddress : txToken?.address || ''
|
const txRecipient = isSendingNativeToken ? tx.recipientAddress : txToken?.address || ''
|
||||||
|
const txValue = isSendingNativeToken ? toTokenUnit(tx.amount, nativeCoin.decimals) : '0'
|
||||||
const txAmount = useTxAmount(tx, isSendingNativeToken, txToken)
|
const data = useTxData(isSendingNativeToken, tx.amount, tx.recipientAddress, txToken)
|
||||||
const data = useTxData(isSendingNativeToken, txAmount, tx.recipientAddress, txToken)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
gasCostFormatted,
|
gasCostFormatted,
|
||||||
|
@ -120,6 +106,7 @@ const ReviewTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactElement =>
|
||||||
} = useEstimateTransactionGas({
|
} = useEstimateTransactionGas({
|
||||||
txData: data,
|
txData: data,
|
||||||
txRecipient,
|
txRecipient,
|
||||||
|
txType: tx.txType,
|
||||||
})
|
})
|
||||||
|
|
||||||
const submitTx = async () => {
|
const submitTx = async () => {
|
||||||
|
@ -152,7 +139,7 @@ const ReviewTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactElement =>
|
||||||
createTransaction({
|
createTransaction({
|
||||||
safeAddress: safeAddress,
|
safeAddress: safeAddress,
|
||||||
to: txRecipient as string,
|
to: txRecipient as string,
|
||||||
valueInWei: txAmount,
|
valueInWei: txValue,
|
||||||
txData: data,
|
txData: data,
|
||||||
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -19,7 +19,7 @@ import enqueueSnackbar from 'src/logic/notifications/store/actions/enqueueSnackb
|
||||||
import { getNotificationsFromTxType, enhanceSnackbarForAction } from 'src/logic/notifications'
|
import { getNotificationsFromTxType, enhanceSnackbarForAction } from 'src/logic/notifications'
|
||||||
import { sameAddress } from 'src/logic/wallets/ethAddresses'
|
import { sameAddress } from 'src/logic/wallets/ethAddresses'
|
||||||
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
|
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 { grantedSelector } from 'src/routes/safe/container/selector'
|
||||||
import updateSafe from 'src/logic/safe/store/actions/updateSafe'
|
import updateSafe from 'src/logic/safe/store/actions/updateSafe'
|
||||||
import Link from 'src/components/layout/Link'
|
import Link from 'src/components/layout/Link'
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import IconButton from '@material-ui/core/IconButton'
|
import IconButton from '@material-ui/core/IconButton'
|
||||||
import Close from '@material-ui/icons/Close'
|
import Close from '@material-ui/icons/Close'
|
||||||
import { withStyles } from '@material-ui/styles'
|
import React, { useEffect, useState } from 'react'
|
||||||
import React from 'react'
|
|
||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch } from 'react-redux'
|
||||||
import { bindActionCreators } from 'redux'
|
|
||||||
|
|
||||||
import { styles } from './style'
|
import { styles } from './style'
|
||||||
|
|
||||||
|
@ -13,17 +11,61 @@ import Button from 'src/components/layout/Button'
|
||||||
import Hairline from 'src/components/layout/Hairline'
|
import Hairline from 'src/components/layout/Hairline'
|
||||||
import Paragraph from 'src/components/layout/Paragraph'
|
import Paragraph from 'src/components/layout/Paragraph'
|
||||||
import Row from 'src/components/layout/Row'
|
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 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 dispatch = useDispatch()
|
||||||
|
const [multiSendCallData, setMultiSendCallData] = useState(EMPTY_DATA)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const calculateUpgradeSafeModal = async () => {
|
||||||
|
const encodeMultiSendCallData = await getUpgradeSafeTransactionHash(safeAddress)
|
||||||
|
setMultiSendCallData(encodeMultiSendCallData)
|
||||||
|
}
|
||||||
|
calculateUpgradeSafeModal()
|
||||||
|
}, [safeAddress])
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
// Call the update safe method
|
// 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()
|
onClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
gasCostFormatted,
|
||||||
|
txEstimationExecutionStatus,
|
||||||
|
isExecution,
|
||||||
|
isCreation,
|
||||||
|
isOffChainSignature,
|
||||||
|
} = useEstimateTransactionGas({
|
||||||
|
txData: multiSendCallData,
|
||||||
|
txRecipient: safeAddress,
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Row align="center" className={classes.heading} grow>
|
<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.
|
have to confirm the update in case more than one confirmation is required for this Safe.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<TransactionFees
|
||||||
|
gasCostFormatted={gasCostFormatted}
|
||||||
|
isExecution={isExecution}
|
||||||
|
isCreation={isCreation}
|
||||||
|
isOffChainSignature={isOffChainSignature}
|
||||||
|
txEstimationExecutionStatus={txEstimationExecutionStatus}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
</Block>
|
</Block>
|
||||||
<Hairline style={{ position: 'absolute', bottom: 85 }} />
|
<Hairline style={{ position: 'absolute', bottom: 85 }} />
|
||||||
<Row align="center" className={classes.buttonRow}>
|
<Row align="center" className={classes.buttonRow}>
|
||||||
|
@ -72,5 +123,3 @@ const UpdateSafeModal = ({ classes, onClose, safeAddress }) => {
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(styles as any)(UpdateSafeModal)
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { lg, md, secondaryText, sm } from 'src/theme/variables'
|
import { lg, md, secondaryText, sm } from 'src/theme/variables'
|
||||||
|
import { createStyles } from '@material-ui/core'
|
||||||
|
|
||||||
export const styles = () => ({
|
export const styles = createStyles({
|
||||||
heading: {
|
heading: {
|
||||||
padding: `${sm} ${lg}`,
|
padding: `${sm} ${lg}`,
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
|
|
@ -105,6 +105,7 @@ export const ApproveTxModal = ({
|
||||||
userAddress,
|
userAddress,
|
||||||
notifiedTransaction: TX_NOTIFICATION_TYPES.CONFIRMATION_TX,
|
notifiedTransaction: TX_NOTIFICATION_TYPES.CONFIRMATION_TX,
|
||||||
approveAndExecute: canExecute && approveAndExecute && isTheTxReadyToBeExecuted,
|
approveAndExecute: canExecute && approveAndExecute && isTheTxReadyToBeExecuted,
|
||||||
|
thresholdReached,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
onClose()
|
onClose()
|
||||||
|
|
|
@ -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 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 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 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
|
* Not being used
|
||||||
export const SQUARELINK_ID = {
|
export const SQUARELINK_ID = {
|
||||||
|
|
82
yarn.lock
82
yarn.lock
|
@ -1782,19 +1782,19 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
invariant "2"
|
invariant "2"
|
||||||
|
|
||||||
"@ledgerhq/devices@^5.36.0":
|
"@ledgerhq/devices@^5.38.0":
|
||||||
version "5.36.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.36.0.tgz#f4493bea44390325fcc7a2a0d03bba69fc1604ec"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.38.0.tgz#0b805020c4f3ac40d35f1b1af6d64d04256b1e0f"
|
||||||
integrity sha512-EwQwLZcz66a2V07Bad0J+Q67LR2afj2NJChJNcA6/gqvzXrtNtJ37u1co9eLU7S5GGll5JGi7KdBqAD9ZTHaaQ==
|
integrity sha512-1RZ+Dh+oVUDMeaPSCeQ56qzgiMHHy481dbkRCDUMRJEzkGqOLI3k34x7XdkVKy1NQdt8G8sYyobP/yixDry5ow==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ledgerhq/errors" "^5.36.0"
|
"@ledgerhq/errors" "^5.38.0"
|
||||||
"@ledgerhq/logs" "^5.36.0"
|
"@ledgerhq/logs" "^5.38.0"
|
||||||
rxjs "^6.6.3"
|
rxjs "^6.6.3"
|
||||||
|
|
||||||
"@ledgerhq/errors@^5.34.0", "@ledgerhq/errors@^5.36.0":
|
"@ledgerhq/errors@^5.34.0", "@ledgerhq/errors@^5.38.0":
|
||||||
version "5.36.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.36.0.tgz#9d178b54116ae81b1fbdfa80afcd33981453be4c"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.38.0.tgz#1642b87de47cbabc7b75ca93005a690895920a72"
|
||||||
integrity sha512-VS6aFzn3IDUmSLaX2kAPg5sQOc5m7IwvswAGvoMc3FCi9/a1dXWwtiYn5rWd1QjDJlTKSfCwmSpvUMp8FKoY2Q==
|
integrity sha512-d4gQzbOLNBoGIwDtEGFNSb0w0aYN10T5Y749e+vqiJoS3dWrB+5BCSQ/U/ALet0wi/UMIyFY/xmgd1gPaPB3Hw==
|
||||||
|
|
||||||
"@ledgerhq/hw-app-eth@^5.21.0":
|
"@ledgerhq/hw-app-eth@^5.21.0":
|
||||||
version "5.37.0"
|
version "5.37.0"
|
||||||
|
@ -1807,27 +1807,27 @@
|
||||||
bignumber.js "^9.0.1"
|
bignumber.js "^9.0.1"
|
||||||
rlp "^2.2.6"
|
rlp "^2.2.6"
|
||||||
|
|
||||||
"@ledgerhq/hw-transport-node-hid-noevents@^5.36.0":
|
"@ledgerhq/hw-transport-node-hid-noevents@^5.38.0":
|
||||||
version "5.36.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.36.0.tgz#a25bdf0d10f9eac73148040e5887f40ca46f6a93"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.38.0.tgz#ffbfb0b997e585fc08b6b220997caaa59e094554"
|
||||||
integrity sha512-8zwokin0KFJaTzhy7oLVcy4QCNUjMuc49wPLnr3zxLqhO1innMp2crUxjIFNLRGJm/TfDLnlpxTPud6WZoo5zg==
|
integrity sha512-zuxN3gWfCuN+pbK3BKc8z3VCulKI7zee1N3xhCWua9TiwL3leBTBs25Bvm22fmiLJYhzszccbF673/bpnnIQAA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ledgerhq/devices" "^5.36.0"
|
"@ledgerhq/devices" "^5.38.0"
|
||||||
"@ledgerhq/errors" "^5.36.0"
|
"@ledgerhq/errors" "^5.38.0"
|
||||||
"@ledgerhq/hw-transport" "^5.36.0"
|
"@ledgerhq/hw-transport" "^5.38.0"
|
||||||
"@ledgerhq/logs" "^5.36.0"
|
"@ledgerhq/logs" "^5.38.0"
|
||||||
node-hid "2.1.1"
|
node-hid "2.1.1"
|
||||||
|
|
||||||
"@ledgerhq/hw-transport-node-hid-singleton@5.36.0":
|
"@ledgerhq/hw-transport-node-hid-singleton@5.38.0":
|
||||||
version "5.36.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-singleton/-/hw-transport-node-hid-singleton-5.36.0.tgz#99cedb773e571642d7f151c3134c5924147bc0d8"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-singleton/-/hw-transport-node-hid-singleton-5.38.0.tgz#ea133ac3a7015aaafd5d629388da4d4a2086c761"
|
||||||
integrity sha512-eKkJGXW0m7PeJY7V/7FDfU4VFLIVSRjxi7PpfJKFYlUrRwx9QndlZT0LD0u3W9dLktgounHhsOuXvuG44uTHYA==
|
integrity sha512-FPpr6R2Cs6YKCamprC9vzJa+P7RieyMLQC3cG6EjYg8tmvHPtIxpmWFclNi45jZ05Ve1YvNjutoHVTVn0cOnpg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ledgerhq/devices" "^5.36.0"
|
"@ledgerhq/devices" "^5.38.0"
|
||||||
"@ledgerhq/errors" "^5.36.0"
|
"@ledgerhq/errors" "^5.38.0"
|
||||||
"@ledgerhq/hw-transport" "^5.36.0"
|
"@ledgerhq/hw-transport" "^5.38.0"
|
||||||
"@ledgerhq/hw-transport-node-hid-noevents" "^5.36.0"
|
"@ledgerhq/hw-transport-node-hid-noevents" "^5.38.0"
|
||||||
"@ledgerhq/logs" "^5.36.0"
|
"@ledgerhq/logs" "^5.38.0"
|
||||||
lodash "^4.17.20"
|
lodash "^4.17.20"
|
||||||
node-hid "2.1.1"
|
node-hid "2.1.1"
|
||||||
usb-detection "^4.10.0"
|
usb-detection "^4.10.0"
|
||||||
|
@ -1842,19 +1842,19 @@
|
||||||
"@ledgerhq/logs" "^5.30.0"
|
"@ledgerhq/logs" "^5.30.0"
|
||||||
u2f-api "0.2.7"
|
u2f-api "0.2.7"
|
||||||
|
|
||||||
"@ledgerhq/hw-transport@^5.34.0", "@ledgerhq/hw-transport@^5.36.0":
|
"@ledgerhq/hw-transport@^5.34.0", "@ledgerhq/hw-transport@^5.38.0":
|
||||||
version "5.36.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.36.0.tgz#b6e951c411182ece59c7b527f948240d1b0a8a51"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.38.0.tgz#b02bea73d77e729d13c367a967df1666f9ef940d"
|
||||||
integrity sha512-rwLTBUsdGCC3Ka4G99sqGbbyVhkVxXd4eWWeOb8gnuKhrTydZGkkP3JdZSHgWSrVRYTAUmkE1AnUmchbfh361w==
|
integrity sha512-CAxvHukCcp+RqaEsSltmBw4Lb1yW42fiF/LTYN7JvCkZyLIQhvkndLDVCgp4hpMdtLK4bkf7RJRElqbN0vRoAQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ledgerhq/devices" "^5.36.0"
|
"@ledgerhq/devices" "^5.38.0"
|
||||||
"@ledgerhq/errors" "^5.36.0"
|
"@ledgerhq/errors" "^5.38.0"
|
||||||
events "^3.2.0"
|
events "^3.2.0"
|
||||||
|
|
||||||
"@ledgerhq/logs@^5.30.0", "@ledgerhq/logs@^5.36.0":
|
"@ledgerhq/logs@^5.30.0", "@ledgerhq/logs@^5.38.0":
|
||||||
version "5.36.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.36.0.tgz#78721347162fb834d90effa1123b363dc46e3a52"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.38.0.tgz#3c5dbd1f62c0bf5580477b218fb57c67b575643a"
|
||||||
integrity sha512-HnD/hByteUL1MsJu1lMinY9bNq8++5mWJ8qHCW9dLC9LbsvWIqwLwmZiGcW0D2tX9p0/C5ESuIpJ9B/d2dReuw==
|
integrity sha512-i87Yn89Cq2D9Y0KmrEzCm62XHzI2edeOTBENKH6vAyzESGzyF+SBoqtZNwrjJcKup3/9dNn/zHjpicY7ev94Vw==
|
||||||
|
|
||||||
"@material-ui/core@^4.11.0":
|
"@material-ui/core@^4.11.0":
|
||||||
version "4.11.2"
|
version "4.11.2"
|
||||||
|
@ -8156,10 +8156,10 @@ electron-updater@4.3.5:
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
electron@^9.3.5:
|
electron@^9.4.0:
|
||||||
version "9.3.5"
|
version "9.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-9.3.5.tgz#7967146b81e6d9b484773243fd4a4f671a50b884"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-9.4.1.tgz#62a2aae4cd93f1b56d794a47541505a71654177a"
|
||||||
integrity sha512-EPmDsp7sO0UPtw7nLD1ufse/nBskP+ifXzBgUg9psCUlapkzuwYi6pmLAzKLW/bVjwgyUKwh1OKWILWfOeLGcQ==
|
integrity sha512-r4CxoVG9Ja7tBtkilWMnBsBGup8G8Z+v7icZmwysHa8/OSr0OrLjrcOF/30BAP7yPE5fz/XTxygnltzW4OTZdw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^1.0.1"
|
"@electron/get" "^1.0.1"
|
||||||
"@types/node" "^12.0.12"
|
"@types/node" "^12.0.12"
|
||||||
|
|
Loading…
Reference in New Issue