Update calculateGasPrice to fetch from config (#1517)

* Update calculateGasPrice to fetch from config

* Remove unused gas estimation function

* Remove unused gasCost estimate function

* Add gasParameter to gasPriceOracle
This commit is contained in:
Daniel Sanchez 2020-10-23 17:18:09 +02:00 committed by GitHub
parent c9e9fe8ca6
commit 5f3a9ef1a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 210 additions and 235 deletions

View File

@ -1,5 +1,5 @@
import networks from 'src/config/networks' import networks from 'src/config/networks'
import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkSettings, SafeFeatures, Wallets } from 'src/config/networks/network.d' import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkSettings, SafeFeatures, Wallets, GasPriceOracle } from 'src/config/networks/network.d'
import { APP_ENV, ETHERSCAN_API_KEY, GOOGLE_ANALYTICS_ID, INFURA_TOKEN, NETWORK, NODE_ENV } from 'src/utils/constants' import { APP_ENV, ETHERSCAN_API_KEY, GOOGLE_ANALYTICS_ID, INFURA_TOKEN, NETWORK, NODE_ENV } from 'src/utils/constants'
import { ensureOnce } from 'src/utils/singleton' import { ensureOnce } from 'src/utils/singleton'
import memoize from 'lodash.memoize' import memoize from 'lodash.memoize'
@ -63,6 +63,10 @@ export const getRelayUrl = (): string | undefined => getConfig()?.relayApiUrl
export const getGnosisSafeAppsUrl = (): string => getConfig()?.safeAppsUrl export const getGnosisSafeAppsUrl = (): string => getConfig()?.safeAppsUrl
export const getGasPrice = (): number | undefined => getConfig()?.gasPrice
export const getGasPriceOracle = (): GasPriceOracle | undefined => getConfig()?.gasPriceOracle
export const getRpcServiceUrl = (): string => { export const getRpcServiceUrl = (): string => {
const usesInfuraRPC = [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY].includes(getNetworkId()) const usesInfuraRPC = [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY].includes(getNetworkId())

View File

@ -5,7 +5,10 @@ const baseConfig: EnvironmentSettings = {
txServiceUrl: 'http://localhost:8000/api/v1', txServiceUrl: 'http://localhost:8000/api/v1',
relayApiUrl: 'https://safe-relay.staging.gnosisdev.com/api/v1', relayApiUrl: 'https://safe-relay.staging.gnosisdev.com/api/v1',
safeAppsUrl: 'http://localhost:3002', safeAppsUrl: 'http://localhost:3002',
gasPriceOracleUrl: 'https://ethgasstation.info/json/ethgasAPI.json', gasPriceOracle: {
url: 'https://ethgasstation.info/json/ethgasAPI.json',
gasParameter: 'average',
},
rpcServiceUrl: 'http://localhost:4447', rpcServiceUrl: 'http://localhost:4447',
networkExplorerName: 'Etherscan', networkExplorerName: 'Etherscan',
networkExplorerUrl: 'https://rinkeby.etherscan.io', networkExplorerUrl: 'https://rinkeby.etherscan.io',

View File

@ -4,7 +4,10 @@ import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkConfig } from 'src/config
const baseConfig: EnvironmentSettings = { const baseConfig: EnvironmentSettings = {
txServiceUrl: 'https://safe-transaction.mainnet.staging.gnosisdev.com/api/v1', txServiceUrl: 'https://safe-transaction.mainnet.staging.gnosisdev.com/api/v1',
safeAppsUrl: 'https://safe-apps.dev.gnosisdev.com', safeAppsUrl: 'https://safe-apps.dev.gnosisdev.com',
gasPriceOracleUrl: 'https://ethgasstation.info/json/ethgasAPI.json', gasPriceOracle: {
url: 'https://ethgasstation.info/json/ethgasAPI.json',
gasParameter: 'average',
},
rpcServiceUrl: 'https://mainnet.infura.io:443/v3', rpcServiceUrl: 'https://mainnet.infura.io:443/v3',
networkExplorerName: 'Etherscan', networkExplorerName: 'Etherscan',
networkExplorerUrl: 'https://etherscan.io', networkExplorerUrl: 'https://etherscan.io',

View File

@ -64,14 +64,20 @@ export type SafeFeatures = FEATURES[]
export type Wallets = WALLETS[] export type Wallets = WALLETS[]
export type GasPriceOracle = {
url: string
// Different gas api providers can use a different name to reflect different gas levels based on tx speed
// For example in ethGasStation for ETHEREUM_MAINNET = safeLow | average | fast
gasParameter: string
}
type GasPrice = { type GasPrice = {
gasPrice: number gasPrice: number
gasPriceOracleUrl?: string gasPriceOracle?: GasPriceOracle
} | { } | {
gasPrice?: number gasPrice?: number
// for infura there's a REST API Token required stored in: `REACT_APP_INFURA_TOKEN` // for infura there's a REST API Token required stored in: `REACT_APP_INFURA_TOKEN`
gasPriceOracleUrl: string gasPriceOracle: GasPriceOracle
} }
export type EnvironmentSettings = GasPrice & { export type EnvironmentSettings = GasPrice & {

View File

@ -4,7 +4,10 @@ import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkConfig } from 'src/config
const baseConfig: EnvironmentSettings = { const baseConfig: EnvironmentSettings = {
txServiceUrl: 'https://safe-transaction.staging.gnosisdev.com/api/v1', txServiceUrl: 'https://safe-transaction.staging.gnosisdev.com/api/v1',
safeAppsUrl: 'https://safe-apps.dev.gnosisdev.com', safeAppsUrl: 'https://safe-apps.dev.gnosisdev.com',
gasPriceOracleUrl: 'https://ethgasstation.info/json/ethgasAPI.json', gasPriceOracle: {
url: 'https://ethgasstation.info/json/ethgasAPI.json',
gasParameter: 'average',
},
rpcServiceUrl: 'https://rinkeby.infura.io:443/v3', rpcServiceUrl: 'https://rinkeby.infura.io:443/v3',
networkExplorerName: 'Etherscan', networkExplorerName: 'Etherscan',
networkExplorerUrl: 'https://rinkeby.etherscan.io', networkExplorerUrl: 'https://rinkeby.etherscan.io',

View File

@ -1,17 +0,0 @@
import axios from 'axios'
import { getRelayUrl } from 'src/config/index'
export const estimateTxGas = (safeAddress, to, value, data, operation = 0) => {
const apiUrl = getRelayUrl()
const url = `${apiUrl}/safes/${safeAddress}/transactions/estimate/`
// const estimationValue = isTokenTransfer(tx.data) ? '0' : value.toString(10)
return axios.post(url, {
safe: safeAddress,
to,
data: '0x',
value,
operation,
})
}

View File

@ -1 +0,0 @@
export * from './estimateTxGas'

View File

@ -16,7 +16,7 @@ import {
saveTxToHistory, saveTxToHistory,
tryOffchainSigning, tryOffchainSigning,
} from 'src/logic/safe/transactions' } from 'src/logic/safe/transactions'
import { estimateSafeTxGas } from 'src/logic/safe/transactions/gasNew' import { estimateSafeTxGas } from 'src/logic/safe/transactions/gas'
import { getCurrentSafeVersion } from 'src/logic/safe/utils/safeVersion' import { getCurrentSafeVersion } from 'src/logic/safe/utils/safeVersion'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions' import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'

View File

@ -1,36 +1,168 @@
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { BigNumber } from 'bignumber.js'
import { AbiItem } from 'web3-utils'
export const calculateTxFee = async (safe, safeAddress, from, data, to, valueInWei, operation) => { import { CALL } from '.'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { generateSignaturesFromTxConfirmations } from 'src/logic/safe/safeTxSigner'
import { Transaction } from 'src/logic/safe/store/models/types/transaction'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { EMPTY_DATA, calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransactions'
import { getAccountFrom, getWeb3 } from 'src/logic/wallets/getWeb3'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
const estimateDataGasCosts = (data: string): number => {
const reducer = (accumulator, currentValue) => {
if (currentValue === EMPTY_DATA) {
return accumulator + 0
}
if (currentValue === '00') {
return accumulator + 4
}
return accumulator + 16
}
return data.match(/.{2}/g)?.reduce(reducer, 0)
}
export const estimateTxGasCosts = async (
safeAddress: string,
to: string,
data: string,
tx?: Transaction,
preApprovingOwner?: string,
): Promise<number> => {
try {
const web3 = getWeb3()
const from = await getAccountFrom(web3)
if (!from) {
return 0
}
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown) as GnosisSafe
const nonce = await safeInstance.methods.nonce().call()
const threshold = await safeInstance.methods.getThreshold().call()
const isExecution = tx?.confirmations.size === Number(threshold) || !!preApprovingOwner || threshold === '1'
let txData
if (isExecution) {
// https://docs.gnosis.io/safe/docs/docs5/#pre-validated-signatures
const signatures = tx?.confirmations
? generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
: `0x000000000000000000000000${from.replace(
'0x',
'',
)}000000000000000000000000000000000000000000000000000000000000000001`
txData = await safeInstance.methods
.execTransaction(
to,
tx?.value || 0,
data,
CALL,
tx?.safeTxGas || 0,
0,
0,
ZERO_ADDRESS,
ZERO_ADDRESS,
signatures,
)
.encodeABI()
} else {
const txHash = await safeInstance.methods
.getTransactionHash(to, tx?.value || 0, data, CALL, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, nonce)
.call({
from,
})
txData = await safeInstance.methods.approveHash(txHash).encodeABI()
}
const gas = await calculateGasOf(txData, from, safeAddress)
const gasPrice = await calculateGasPrice()
return gas * parseInt(gasPrice, 10)
} catch (err) {
console.error('Error while estimating transaction execution gas costs:')
console.error(err)
return 10000
}
}
export const estimateSafeTxGas = async (
safe: GnosisSafe | undefined,
safeAddress: string,
data: string,
to: string,
valueInWei: string,
operation: number,
): Promise<number> => {
try { try {
let safeInstance = safe let safeInstance = safe
if (!safeInstance) { if (!safeInstance) {
safeInstance = await getGnosisSafeInstanceAt(safeAddress) safeInstance = await getGnosisSafeInstanceAt(safeAddress)
} }
// https://docs.gnosis.io/safe/docs/docs5/#pre-validated-signatures const web3 = await getWeb3()
const sigs = `0x000000000000000000000000${from.replace( const estimateData = safeInstance.methods.requiredTxGas(to, valueInWei, data, operation).encodeABI()
'0x', const estimateResponse = await web3.eth.call({
'', to: safeAddress,
)}000000000000000000000000000000000000000000000000000000000000000001` from: safeAddress,
data: estimateData,
})
const txGasEstimation = new BigNumber(estimateResponse.substring(138), 16).toNumber() + 10000
// we get gas limit from this call, then it needs to be multiplied by the gas price // 21000 - additional gas costs (e.g. base tx costs, transfer costs)
// https://safe-relay.gnosis.pm/api/v1/gas-station/ const dataGasEstimation = estimateDataGasCosts(estimateData) + 21000
// https://safe-relay.rinkeby.gnosis.pm/api/v1/about/ const additionalGasBatches = [10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000]
const estimate = await safeInstance.execTransaction.estimateGas(
to, const batch = new web3.BatchRequest()
valueInWei, const estimationRequests = additionalGasBatches.map(
data, (additionalGas) =>
operation, new Promise((resolve) => {
0, // there are no type definitions for .request, so for now ts-ignore is there
0, // Issue link: https://github.com/ethereum/web3.js/issues/3144
0, // eslint-disable-next-line
'0x0000000000000000000000000000000000000000', // @ts-ignore
'0x0000000000000000000000000000000000000000', const request = web3.eth.call.request(
sigs, {
{ from: '0xbc2BB26a6d821e69A38016f3858561a1D80d4182' }, to: safeAddress,
from: safeAddress,
data: estimateData,
gasPrice: 0,
gasLimit: txGasEstimation + dataGasEstimation + additionalGas,
},
(error, res) => {
// res.data check is for OpenEthereum/Parity revert messages format
const isOpenEthereumRevertMsg = res && typeof res.data === 'string'
const isEstimationSuccessful =
!error &&
((typeof res === 'string' && res !== '0x') || (isOpenEthereumRevertMsg && res.data.slice(9) !== '0x'))
resolve({
success: isEstimationSuccessful,
estimation: txGasEstimation + additionalGas,
})
},
)
batch.add(request)
}),
) )
batch.execute()
return estimate const estimationResponses = await Promise.all(estimationRequests)
const firstSuccessfulRequest: any = estimationResponses.find((res: any) => res.success)
if (firstSuccessfulRequest) {
return firstSuccessfulRequest.estimation
}
return 0
} catch (error) { } catch (error) {
console.error('Error calculating tx gas estimation', error) console.error('Error calculating tx gas estimation', error)
return 0 return 0

View File

@ -1,170 +0,0 @@
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { BigNumber } from 'bignumber.js'
import { AbiItem } from 'web3-utils'
import { CALL } from '.'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { generateSignaturesFromTxConfirmations } from 'src/logic/safe/safeTxSigner'
import { Transaction } from 'src/logic/safe/store/models/types/transaction'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { EMPTY_DATA, calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransactions'
import { getAccountFrom, getWeb3 } from 'src/logic/wallets/getWeb3'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
const estimateDataGasCosts = (data: string): number => {
const reducer = (accumulator, currentValue) => {
if (currentValue === EMPTY_DATA) {
return accumulator + 0
}
if (currentValue === '00') {
return accumulator + 4
}
return accumulator + 16
}
return data.match(/.{2}/g)?.reduce(reducer, 0)
}
export const estimateTxGasCosts = async (
safeAddress: string,
to: string,
data: string,
tx?: Transaction,
preApprovingOwner?: string,
): Promise<number> => {
try {
const web3 = getWeb3()
const from = await getAccountFrom(web3)
if (!from) {
return 0
}
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown) as GnosisSafe
const nonce = await safeInstance.methods.nonce().call()
const threshold = await safeInstance.methods.getThreshold().call()
const isExecution = tx?.confirmations.size === Number(threshold) || !!preApprovingOwner || threshold === '1'
let txData
if (isExecution) {
// https://docs.gnosis.io/safe/docs/docs5/#pre-validated-signatures
const signatures = tx?.confirmations
? generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
: `0x000000000000000000000000${from.replace(
'0x',
'',
)}000000000000000000000000000000000000000000000000000000000000000001`
txData = await safeInstance.methods
.execTransaction(
to,
tx?.value || 0,
data,
CALL,
tx?.safeTxGas || 0,
0,
0,
ZERO_ADDRESS,
ZERO_ADDRESS,
signatures,
)
.encodeABI()
} else {
const txHash = await safeInstance.methods
.getTransactionHash(to, tx?.value || 0, data, CALL, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, nonce)
.call({
from,
})
txData = await safeInstance.methods.approveHash(txHash).encodeABI()
}
const gas = await calculateGasOf(txData, from, safeAddress)
const gasPrice = await calculateGasPrice()
return gas * parseInt(gasPrice, 10)
} catch (err) {
console.error('Error while estimating transaction execution gas costs:')
console.error(err)
return 10000
}
}
export const estimateSafeTxGas = async (
safe: GnosisSafe | undefined,
safeAddress: string,
data: string,
to: string,
valueInWei: string,
operation: number,
): Promise<number> => {
try {
let safeInstance = safe
if (!safeInstance) {
safeInstance = await getGnosisSafeInstanceAt(safeAddress)
}
const web3 = await getWeb3()
const estimateData = safeInstance.methods.requiredTxGas(to, valueInWei, data, operation).encodeABI()
const estimateResponse = await web3.eth.call({
to: safeAddress,
from: safeAddress,
data: estimateData,
})
const txGasEstimation = new BigNumber(estimateResponse.substring(138), 16).toNumber() + 10000
// 21000 - additional gas costs (e.g. base tx costs, transfer costs)
const dataGasEstimation = estimateDataGasCosts(estimateData) + 21000
const additionalGasBatches = [10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000]
const batch = new web3.BatchRequest()
const estimationRequests = additionalGasBatches.map(
(additionalGas) =>
new Promise((resolve) => {
// there are no type definitions for .request, so for now ts-ignore is there
// Issue link: https://github.com/ethereum/web3.js/issues/3144
// eslint-disable-next-line
// @ts-ignore
const request = web3.eth.call.request(
{
to: safeAddress,
from: safeAddress,
data: estimateData,
gasPrice: 0,
gasLimit: txGasEstimation + dataGasEstimation + additionalGas,
},
(error, res) => {
// res.data check is for OpenEthereum/Parity revert messages format
const isOpenEthereumRevertMsg = res && typeof res.data === 'string'
const isEstimationSuccessful =
!error &&
((typeof res === 'string' && res !== '0x') || (isOpenEthereumRevertMsg && res.data.slice(9) !== '0x'))
resolve({
success: isEstimationSuccessful,
estimation: txGasEstimation + additionalGas,
})
},
)
batch.add(request)
}),
)
batch.execute()
const estimationResponses = await Promise.all(estimationRequests)
const firstSuccessfulRequest: any = estimationResponses.find((res: any) => res.success)
if (firstSuccessfulRequest) {
return firstSuccessfulRequest.estimation
}
return 0
} catch (error) {
console.error('Error calculating tx gas estimation', error)
return 0
}
}

View File

@ -1,4 +1,3 @@
export * from './gas'
export * from './send' export * from './send'
export * from './offchainSigner' export * from './offchainSigner'
export * from './txHistory' export * from './txHistory'

View File

@ -2,6 +2,7 @@ import axios from 'axios'
import { BigNumber } from 'bignumber.js' import { BigNumber } from 'bignumber.js'
import { getWeb3, web3ReadOnly } from 'src/logic/wallets/getWeb3' import { getWeb3, web3ReadOnly } from 'src/logic/wallets/getWeb3'
import { getGasPrice, getGasPriceOracle } from 'src/config'
// const MAINNET_NETWORK = 1 // const MAINNET_NETWORK = 1
export const EMPTY_DATA = '0x' export const EMPTY_DATA = '0x'
@ -26,7 +27,7 @@ export const checkReceiptStatus = async (hash) => {
return Promise.resolve() return Promise.resolve()
} }
export const calculateGasPrice = async () => { export const calculateGasPrice = async (): Promise<string> => {
/* /*
const web3 = getWeb3() const web3 = getWeb3()
const { network } = web3.version const { network } = web3.version
@ -41,11 +42,23 @@ export const calculateGasPrice = async () => {
return '20000000000' return '20000000000'
} }
const url = 'https://ethgasstation.info/json/ethgasAPI.json' const gasPrice = getGasPrice()
// const errMsg = 'Error querying gas station' const gasPriceOracle = getGasPriceOracle()
const { data } = await axios.get(url)
return new BigNumber(data.average).multipliedBy(1e8).toString() if (gasPrice) {
// Fixed gas price in configuration. xDai uses this approach
return new BigNumber(gasPrice).toString()
} else if (gasPriceOracle) {
const { url, gasParameter } = gasPriceOracle
// Fetch from gas price provider
const { data } = await axios.get(url)
return new BigNumber(data[gasParameter]).multipliedBy(1e8).toString()
} else {
const errorMsg = 'gasPrice or gasPriceOracle not set in config'
return Promise.reject(errorMsg)
}
} }
export const calculateGasOf = async (data, from, to) => { export const calculateGasOf = async (data, from, to) => {

View File

@ -20,7 +20,7 @@ import createTransaction from 'src/logic/safe/store/actions/createTransaction'
import { MULTI_SEND_ADDRESS } from 'src/logic/contracts/safeContracts' import { MULTI_SEND_ADDRESS } from 'src/logic/contracts/safeContracts'
import { DELEGATE_CALL, TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { DELEGATE_CALL, TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { encodeMultiSendCall } from 'src/logic/safe/transactions/multisend' import { encodeMultiSendCall } from 'src/logic/safe/transactions/multisend'
import { estimateSafeTxGas } from 'src/logic/safe/transactions/gasNew' import { estimateSafeTxGas } from 'src/logic/safe/transactions/gas'
import GasEstimationInfo from './GasEstimationInfo' import GasEstimationInfo from './GasEstimationInfo'
import { getNetworkInfo } from 'src/config' import { getNetworkInfo } from 'src/config'

View File

@ -14,7 +14,7 @@ import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import { AbiItemExtended } from 'src/logic/contractInteraction/sources/ABIService' import { AbiItemExtended } from 'src/logic/contractInteraction/sources/ABIService'
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers' import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers'
import { styles } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/style' import { styles } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/style'

View File

@ -19,7 +19,7 @@ import Row from 'src/components/layout/Row'
import createTransaction from 'src/logic/safe/store/actions/createTransaction' import createTransaction from 'src/logic/safe/store/actions/createTransaction'
import { safeSelector } from 'src/logic/safe/store/selectors' import { safeSelector } from 'src/logic/safe/store/selectors'
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers' import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers'
import SafeInfo from 'src/routes/safe/components/Balances/SendModal/SafeInfo' import SafeInfo from 'src/routes/safe/components/Balances/SendModal/SafeInfo'

View File

@ -20,7 +20,7 @@ import { nftTokensSelector } from 'src/logic/collectibles/store/selectors'
import createTransaction from 'src/logic/safe/store/actions/createTransaction' import createTransaction from 'src/logic/safe/store/actions/createTransaction'
import { safeSelector } from 'src/logic/safe/store/selectors' import { safeSelector } from 'src/logic/safe/store/selectors'
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { import {
containsMethodByHash, containsMethodByHash,
getERC721TokenContract, getERC721TokenContract,

View File

@ -21,7 +21,7 @@ import Row from 'src/components/layout/Row'
import createTransaction from 'src/logic/safe/store/actions/createTransaction' import createTransaction from 'src/logic/safe/store/actions/createTransaction'
import { safeSelector } from 'src/logic/safe/store/selectors' import { safeSelector } from 'src/logic/safe/store/selectors'
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { getHumanFriendlyToken } from 'src/logic/tokens/store/actions/fetchTokens' import { getHumanFriendlyToken } from 'src/logic/tokens/store/actions/fetchTokens'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions' import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'

View File

@ -17,7 +17,7 @@ import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { safeNameSelector, safeOwnersSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors' import { safeNameSelector, safeOwnersSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { styles } from './style' import { styles } from './style'

View File

@ -17,7 +17,7 @@ import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import { getGnosisSafeInstanceAt, SENTINEL_ADDRESS } from 'src/logic/contracts/safeContracts' import { getGnosisSafeInstanceAt, SENTINEL_ADDRESS } from 'src/logic/contracts/safeContracts'
import { safeNameSelector, safeOwnersSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors' import { safeNameSelector, safeOwnersSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { styles } from './style' import { styles } from './style'

View File

@ -22,7 +22,7 @@ import {
safeParamAddressFromStateSelector, safeParamAddressFromStateSelector,
safeThresholdSelector, safeThresholdSelector,
} from 'src/logic/safe/store/selectors' } from 'src/logic/safe/store/selectors'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { styles } from './style' import { styles } from './style'

View File

@ -18,7 +18,7 @@ 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 { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
const THRESHOLD_FIELD_NAME = 'threshold' const THRESHOLD_FIELD_NAME = 'threshold'

View File

@ -18,7 +18,7 @@ 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 { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { userAccountSelector } from 'src/logic/wallets/store/selectors' import { userAccountSelector } from 'src/logic/wallets/store/selectors'
import processTransaction from 'src/logic/safe/store/actions/processTransaction' import processTransaction from 'src/logic/safe/store/actions/processTransaction'

View File

@ -16,7 +16,7 @@ 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 { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import { estimateTxGasCosts } from 'src/logic/safe/transactions/gasNew' import { estimateTxGasCosts } from 'src/logic/safe/transactions/gas'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions' import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
import createTransaction from 'src/logic/safe/store/actions/createTransaction' import createTransaction from 'src/logic/safe/store/actions/createTransaction'