From 921b039104e61b28898c48e729c9cd359cedf7f2 Mon Sep 17 00:00:00 2001 From: nicosampler Date: Thu, 19 Nov 2020 17:23:30 -0300 Subject: [PATCH 01/11] partial imp --- .prettierignore | 5 +- .../contracts/api/fetchValidMasterCopies.ts | 17 ++++ src/logic/contracts/safeContracts.ts | 91 +++++++++++++------ .../load/components/DetailsForm/index.tsx | 19 +--- src/routes/open/components/Layout.tsx | 4 +- src/routes/open/container/Open.tsx | 1 - src/routes/opening/index.tsx | 4 +- 7 files changed, 86 insertions(+), 55 deletions(-) create mode 100644 src/logic/contracts/api/fetchValidMasterCopies.ts diff --git a/.prettierignore b/.prettierignore index 0b56bd824e..6684fd0bd5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,7 @@ !.eslintrc.js build -config -contracts +/config +/contracts flow-typed flow-typed/npm migrations @@ -9,5 +9,4 @@ node_modules public scripts src/assets -src/config test \ No newline at end of file diff --git a/src/logic/contracts/api/fetchValidMasterCopies.ts b/src/logic/contracts/api/fetchValidMasterCopies.ts new file mode 100644 index 0000000000..96512968be --- /dev/null +++ b/src/logic/contracts/api/fetchValidMasterCopies.ts @@ -0,0 +1,17 @@ +import axios from 'axios' +import { getTxServiceUrl } from 'src/config' + +type MasterCopies = { + address: string + version: string +} + +export const getValidMasterCopies = async (): Promise => { + const url = `${getTxServiceUrl()}/about/master-copies/` + try { + const res = await axios.get(url) + return res.data + } catch (error) { + console.error('Fetching data from master-copies errored', error) + } +} diff --git a/src/logic/contracts/safeContracts.ts b/src/logic/contracts/safeContracts.ts index cc85b84617..e0846ad604 100644 --- a/src/logic/contracts/safeContracts.ts +++ b/src/logic/contracts/safeContracts.ts @@ -3,6 +3,7 @@ import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe. import memoize from 'lodash.memoize' import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json' import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json' +import IProxySol from '@gnosis.pm/safe-contracts/build/contracts/IProxy.json' import Web3 from 'web3' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' @@ -12,6 +13,8 @@ import { calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransact import { getWeb3, getNetworkIdFrom } from 'src/logic/wallets/getWeb3' import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d' import { GnosisSafeProxyFactory } from 'src/types/contracts/GnosisSafeProxyFactory.d' +import { IProxy } from 'src/types/contracts/IProxy' +import { getValidMasterCopies } from './api/fetchValidMasterCopies' export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001' export const MULTI_SEND_ADDRESS = '0x8d29be29923b68abfdd21e541b9374737b49cdad' @@ -19,6 +22,7 @@ export const SAFE_MASTER_COPY_ADDRESS = '0x34CfAC646f301356fAa8B21e94227e3583Fe3 export const DEFAULT_FALLBACK_HANDLER_ADDRESS = '0xd5D82B6aDDc9027B22dCA772Aa68D5d74cdBdF44' export const SAFE_MASTER_COPY_ADDRESS_V10 = '0xb6029EA3B2c51D09a50B53CA8012FeEB05bDa35A' +const web3 = getWeb3() let proxyFactoryMaster: GnosisSafeProxyFactory let safeMaster: GnosisSafe @@ -28,57 +32,71 @@ let safeMaster: GnosisSafe * @param {Web3} web3 * @param {ETHEREUM_NETWORK} networkId */ -const createGnosisSafeContract = (web3: Web3, networkId: ETHEREUM_NETWORK) => { +export const getGnosisSafeContract = memoize((networkId: ETHEREUM_NETWORK) => { const networks = GnosisSafeSol.networks // TODO: this may not be the most scalable approach, // but up until v1.2.0 the address is the same for all the networks. // So, if we can't find the network in the Contract artifact, we fallback to MAINNET. const contractAddress = networks[networkId]?.address ?? networks[ETHEREUM_NETWORK.MAINNET].address - return new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], contractAddress) as unknown as GnosisSafe -} + return (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], contractAddress) as unknown) as GnosisSafe +}) /** * Creates a Contract instance of the GnosisSafeProxyFactory contract * @param {Web3} web3 * @param {ETHEREUM_NETWORK} networkId */ -const createProxyFactoryContract = (web3: Web3, networkId: ETHEREUM_NETWORK): GnosisSafeProxyFactory => { - const networks = ProxyFactorySol.networks - // TODO: this may not be the most scalable approach, - // but up until v1.2.0 the address is the same for all the networks. - // So, if we can't find the network in the Contract artifact, we fallback to MAINNET. - const contractAddress = networks[networkId]?.address ?? networks[ETHEREUM_NETWORK.MAINNET].address - return new web3.eth.Contract(ProxyFactorySol.abi as AbiItem[], contractAddress) as unknown as GnosisSafeProxyFactory +const getProxyFactoryContract = memoize( + (networkId: ETHEREUM_NETWORK): GnosisSafeProxyFactory => { + const networks = ProxyFactorySol.networks + // TODO: this may not be the most scalable approach, + // but up until v1.2.0 the address is the same for all the networks. + // So, if we can't find the network in the Contract artifact, we fallback to MAINNET. + const contractAddress = networks[networkId]?.address ?? networks[ETHEREUM_NETWORK.MAINNET].address + return (new web3.eth.Contract( + ProxyFactorySol.abi as AbiItem[], + contractAddress, + ) as unknown) as GnosisSafeProxyFactory + }, +) + +const getMasterCopyAddressFromProxyAddress = async (proxyAddress: string): Promise => { + const proxyInstance = (new web3.eth.Contract(IProxySol.abi as AbiItem[], proxyAddress) as unknown) as IProxy + return await proxyInstance.methods.masterCopy().call() } -export const getGnosisSafeContract = memoize(createGnosisSafeContract) - -const getCreateProxyFactoryContract = memoize(createProxyFactoryContract) - -const instantiateMasterCopies = async () => { - const web3 = getWeb3() +export const instantiateSafeContracts = async () => { const networkId = await getNetworkIdFrom(web3) // Create ProxyFactory Master Copy - proxyFactoryMaster = getCreateProxyFactoryContract(web3, networkId) + proxyFactoryMaster = getProxyFactoryContract(networkId) // Create Safe Master copy - safeMaster = getGnosisSafeContract(web3, networkId) + safeMaster = getGnosisSafeContract(networkId) } -export const initContracts = instantiateMasterCopies - export const getSafeMasterContract = async () => { - await initContracts() - + await instantiateSafeContracts() return safeMaster } -export const getSafeDeploymentTransaction = (safeAccounts: string[], numConfirmations: number, safeCreationSalt: number) => { +export const getSafeDeploymentTransaction = ( + safeAccounts: string[], + numConfirmations: number, + safeCreationSalt: number, +) => { const gnosisSafeData = safeMaster.methods - .setup(safeAccounts, numConfirmations, ZERO_ADDRESS, '0x', DEFAULT_FALLBACK_HANDLER_ADDRESS, ZERO_ADDRESS, 0, ZERO_ADDRESS) + .setup( + safeAccounts, + numConfirmations, + ZERO_ADDRESS, + '0x', + DEFAULT_FALLBACK_HANDLER_ADDRESS, + ZERO_ADDRESS, + 0, + ZERO_ADDRESS, + ) .encodeABI() - return proxyFactoryMaster.methods.createProxyWithNonce(safeMaster.options.address, gnosisSafeData, safeCreationSalt) } @@ -86,10 +104,19 @@ export const estimateGasForDeployingSafe = async ( safeAccounts: string[], numConfirmations: number, userAccount: string, - safeCreationSalt: number + safeCreationSalt: number, ) => { const gnosisSafeData = await safeMaster.methods - .setup(safeAccounts, numConfirmations, ZERO_ADDRESS, '0x', DEFAULT_FALLBACK_HANDLER_ADDRESS, ZERO_ADDRESS, 0, ZERO_ADDRESS) + .setup( + safeAccounts, + numConfirmations, + ZERO_ADDRESS, + '0x', + DEFAULT_FALLBACK_HANDLER_ADDRESS, + ZERO_ADDRESS, + 0, + ZERO_ADDRESS, + ) .encodeABI() const proxyFactoryData = proxyFactoryMaster.methods .createProxyWithNonce(safeMaster.options.address, gnosisSafeData, safeCreationSalt) @@ -101,8 +128,13 @@ export const estimateGasForDeployingSafe = async ( } export const getGnosisSafeInstanceAt = (safeAddress: string): GnosisSafe => { - const web3 = getWeb3() - return new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown as GnosisSafe + return (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown) as GnosisSafe +} + +export const isMasterCopyValid = async (safeAddress: string): Promise => { + const masterCopyAddress = await getMasterCopyAddressFromProxyAddress(safeAddress) + const res = await getValidMasterCopies() + return !res ? false : res.some((mc) => mc.address === masterCopyAddress) } const cleanByteCodeMetadata = (bytecode: string): string => { @@ -125,6 +157,5 @@ export const validateProxy = async (safeAddress: string): Promise => { } } - return isProxyCode(codeWithoutMetadata) } diff --git a/src/routes/load/components/DetailsForm/index.tsx b/src/routes/load/components/DetailsForm/index.tsx index 1524f9e122..d5f118c7d5 100644 --- a/src/routes/load/components/DetailsForm/index.tsx +++ b/src/routes/load/components/DetailsForm/index.tsx @@ -20,8 +20,7 @@ import { import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' import Paragraph from 'src/components/layout/Paragraph' -import { SAFE_MASTER_COPY_ADDRESS_V10, getSafeMasterContract, validateProxy } from 'src/logic/contracts/safeContracts' -import { getWeb3 } from 'src/logic/wallets/getWeb3' +import { isMasterCopyValid, validateProxy } from 'src/logic/contracts/safeContracts' import { FIELD_LOAD_ADDRESS, FIELD_LOAD_NAME } from 'src/routes/load/components/fields' import { secondary } from 'src/theme/variables' @@ -50,7 +49,6 @@ export const SAFE_MASTERCOPY_ERROR = 'Address is not a Safe or mastercopy is not // Don't mind to check if everything is OK inside this function :) export const safeFieldsValidation = async (values): Promise> => { const errors = {} - const web3 = getWeb3() const safeAddress = values[FIELD_LOAD_ADDRESS] if (!safeAddress || mustBeEthereumAddress(safeAddress) !== undefined) { @@ -63,20 +61,7 @@ export const safeFieldsValidation = async (values): Promise { useEffect(() => { if (provider) { - initContracts() + instantiateSafeContracts() } }, [provider]) diff --git a/src/routes/open/container/Open.tsx b/src/routes/open/container/Open.tsx index 7161c4e787..1af1761397 100644 --- a/src/routes/open/container/Open.tsx +++ b/src/routes/open/container/Open.tsx @@ -62,7 +62,6 @@ export const createSafe = (values, userAccount) => { const safeCreationSalt = getSafeCreationSaltFrom(values) const deploymentTx = getSafeDeploymentTransaction(ownerAddresses, confirmations, safeCreationSalt) - const promiEvent = deploymentTx.send({ from: userAccount }) promiEvent diff --git a/src/routes/opening/index.tsx b/src/routes/opening/index.tsx index d976284625..28fd8f817e 100644 --- a/src/routes/opening/index.tsx +++ b/src/routes/opening/index.tsx @@ -9,7 +9,7 @@ import Button from 'src/components/layout/Button' import Heading from 'src/components/layout/Heading' import Img from 'src/components/layout/Img' import Paragraph from 'src/components/layout/Paragraph' -import { initContracts } from 'src/logic/contracts/safeContracts' +import { instantiateSafeContracts } from 'src/logic/contracts/safeContracts' import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions' import { getWeb3 } from 'src/logic/wallets/getWeb3' import { background, connected } from 'src/theme/variables' @@ -152,7 +152,7 @@ const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, submitte useEffect(() => { const loadContracts = async () => { - await initContracts() + await instantiateSafeContracts() setLoading(false) } From 517ddd99003555ec2bcd809180f712d97f7602c0 Mon Sep 17 00:00:00 2001 From: nicosampler Date: Thu, 19 Nov 2020 17:30:21 -0300 Subject: [PATCH 02/11] remove unused type --- src/logic/contracts/safeContracts.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logic/contracts/safeContracts.ts b/src/logic/contracts/safeContracts.ts index e0846ad604..4689e4ef9f 100644 --- a/src/logic/contracts/safeContracts.ts +++ b/src/logic/contracts/safeContracts.ts @@ -4,7 +4,6 @@ import memoize from 'lodash.memoize' import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json' import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json' import IProxySol from '@gnosis.pm/safe-contracts/build/contracts/IProxy.json' -import Web3 from 'web3' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' import { isProxyCode } from 'src/logic/contracts/historicProxyCode' From dc1b0b99a39173dbd4cebd615c6b010860781538 Mon Sep 17 00:00:00 2001 From: nicosampler Date: Thu, 19 Nov 2020 18:04:10 -0300 Subject: [PATCH 03/11] fix web3 issue --- src/logic/contracts/safeContracts.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/logic/contracts/safeContracts.ts b/src/logic/contracts/safeContracts.ts index 4689e4ef9f..91fe62ee9a 100644 --- a/src/logic/contracts/safeContracts.ts +++ b/src/logic/contracts/safeContracts.ts @@ -4,6 +4,7 @@ import memoize from 'lodash.memoize' import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json' import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json' import IProxySol from '@gnosis.pm/safe-contracts/build/contracts/IProxy.json' +import Web3 from 'web3' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' import { isProxyCode } from 'src/logic/contracts/historicProxyCode' @@ -21,8 +22,6 @@ export const SAFE_MASTER_COPY_ADDRESS = '0x34CfAC646f301356fAa8B21e94227e3583Fe3 export const DEFAULT_FALLBACK_HANDLER_ADDRESS = '0xd5D82B6aDDc9027B22dCA772Aa68D5d74cdBdF44' export const SAFE_MASTER_COPY_ADDRESS_V10 = '0xb6029EA3B2c51D09a50B53CA8012FeEB05bDa35A' -const web3 = getWeb3() - let proxyFactoryMaster: GnosisSafeProxyFactory let safeMaster: GnosisSafe @@ -31,7 +30,7 @@ let safeMaster: GnosisSafe * @param {Web3} web3 * @param {ETHEREUM_NETWORK} networkId */ -export const getGnosisSafeContract = memoize((networkId: ETHEREUM_NETWORK) => { +export const getGnosisSafeContract = memoize((web3: Web3, networkId: ETHEREUM_NETWORK) => { const networks = GnosisSafeSol.networks // TODO: this may not be the most scalable approach, // but up until v1.2.0 the address is the same for all the networks. @@ -46,7 +45,7 @@ export const getGnosisSafeContract = memoize((networkId: ETHEREUM_NETWORK) => { * @param {ETHEREUM_NETWORK} networkId */ const getProxyFactoryContract = memoize( - (networkId: ETHEREUM_NETWORK): GnosisSafeProxyFactory => { + (web3: Web3, networkId: ETHEREUM_NETWORK): GnosisSafeProxyFactory => { const networks = ProxyFactorySol.networks // TODO: this may not be the most scalable approach, // but up until v1.2.0 the address is the same for all the networks. @@ -60,18 +59,20 @@ const getProxyFactoryContract = memoize( ) const getMasterCopyAddressFromProxyAddress = async (proxyAddress: string): Promise => { + const web3 = getWeb3() const proxyInstance = (new web3.eth.Contract(IProxySol.abi as AbiItem[], proxyAddress) as unknown) as IProxy - return await proxyInstance.methods.masterCopy().call() + return proxyInstance.methods.masterCopy().call() } export const instantiateSafeContracts = async () => { + const web3 = getWeb3() const networkId = await getNetworkIdFrom(web3) // Create ProxyFactory Master Copy - proxyFactoryMaster = getProxyFactoryContract(networkId) + proxyFactoryMaster = getProxyFactoryContract(web3, networkId) // Create Safe Master copy - safeMaster = getGnosisSafeContract(networkId) + safeMaster = getGnosisSafeContract(web3, networkId) } export const getSafeMasterContract = async () => { @@ -127,6 +128,7 @@ export const estimateGasForDeployingSafe = async ( } export const getGnosisSafeInstanceAt = (safeAddress: string): GnosisSafe => { + const web3 = getWeb3() return (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown) as GnosisSafe } From 6ff7b92b7154bf7858a1b9ab692308c48146a43b Mon Sep 17 00:00:00 2001 From: nicosampler Date: Fri, 20 Nov 2020 11:14:37 -0300 Subject: [PATCH 04/11] update settings --- .../contracts/api/fetchValidMasterCopies.ts | 17 -- src/logic/contracts/api/masterCopies.ts | 47 +++++ src/logic/contracts/safeContracts.ts | 6 +- .../components/Settings/SafeDetails/index.tsx | 171 ++++++++++-------- 4 files changed, 149 insertions(+), 92 deletions(-) delete mode 100644 src/logic/contracts/api/fetchValidMasterCopies.ts create mode 100644 src/logic/contracts/api/masterCopies.ts diff --git a/src/logic/contracts/api/fetchValidMasterCopies.ts b/src/logic/contracts/api/fetchValidMasterCopies.ts deleted file mode 100644 index 96512968be..0000000000 --- a/src/logic/contracts/api/fetchValidMasterCopies.ts +++ /dev/null @@ -1,17 +0,0 @@ -import axios from 'axios' -import { getTxServiceUrl } from 'src/config' - -type MasterCopies = { - address: string - version: string -} - -export const getValidMasterCopies = async (): Promise => { - const url = `${getTxServiceUrl()}/about/master-copies/` - try { - const res = await axios.get(url) - return res.data - } catch (error) { - console.error('Fetching data from master-copies errored', error) - } -} diff --git a/src/logic/contracts/api/masterCopies.ts b/src/logic/contracts/api/masterCopies.ts new file mode 100644 index 0000000000..b6847d5b70 --- /dev/null +++ b/src/logic/contracts/api/masterCopies.ts @@ -0,0 +1,47 @@ +import axios from 'axios' +import { getTxServiceUrl } from 'src/config' +import memoize from 'lodash.memoize' + +export enum MasterCopyDeployer { + GNOSIS = 'Gnosis', + CIRCLE = 'Circle', +} + +type MasterCopyFetch = { + address: string + version: string +} + +export type MasterCopy = { + address: string + version: string + deployer: MasterCopyDeployer + deployerRepoUrl: string +} + +const extractMasterCopyInfo = (mc: MasterCopyFetch): MasterCopy => { + const dashIndex = mc.version.indexOf('-') + + const masterCopy = { + address: mc.address, + version: dashIndex === -1 ? mc.version : mc.version.substring(0, dashIndex), + deployer: dashIndex === -1 ? MasterCopyDeployer.GNOSIS : MasterCopyDeployer.CIRCLE, + deployerRepoUrl: + dashIndex === -1 + ? 'https://github.com/gnosis/safe-contracts/releases' + : 'https://github.com/CirclesUBI/safe-contracts/releases', + } + return masterCopy +} + +export const fetchMasterCopies = memoize( + async (): Promise => { + const url = `${getTxServiceUrl()}/about/master-copies/` + try { + const res = await axios.get<{ address: string; version: string }[]>(url) + return res.data.map(extractMasterCopyInfo) + } catch (error) { + console.error('Fetching data from master-copies errored', error) + } + }, +) diff --git a/src/logic/contracts/safeContracts.ts b/src/logic/contracts/safeContracts.ts index 91fe62ee9a..0a6224ad3e 100644 --- a/src/logic/contracts/safeContracts.ts +++ b/src/logic/contracts/safeContracts.ts @@ -14,7 +14,7 @@ import { getWeb3, getNetworkIdFrom } from 'src/logic/wallets/getWeb3' import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d' import { GnosisSafeProxyFactory } from 'src/types/contracts/GnosisSafeProxyFactory.d' import { IProxy } from 'src/types/contracts/IProxy' -import { getValidMasterCopies } from './api/fetchValidMasterCopies' +import { fetchMasterCopies } from './api/masterCopies' export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001' export const MULTI_SEND_ADDRESS = '0x8d29be29923b68abfdd21e541b9374737b49cdad' @@ -58,7 +58,7 @@ const getProxyFactoryContract = memoize( }, ) -const getMasterCopyAddressFromProxyAddress = async (proxyAddress: string): Promise => { +export const getMasterCopyAddressFromProxyAddress = async (proxyAddress: string): Promise => { const web3 = getWeb3() const proxyInstance = (new web3.eth.Contract(IProxySol.abi as AbiItem[], proxyAddress) as unknown) as IProxy return proxyInstance.methods.masterCopy().call() @@ -134,7 +134,7 @@ export const getGnosisSafeInstanceAt = (safeAddress: string): GnosisSafe => { export const isMasterCopyValid = async (safeAddress: string): Promise => { const masterCopyAddress = await getMasterCopyAddressFromProxyAddress(safeAddress) - const res = await getValidMasterCopies() + const res = await fetchMasterCopies() return !res ? false : res.some((mc) => mc.address === masterCopyAddress) } diff --git a/src/routes/safe/components/Settings/SafeDetails/index.tsx b/src/routes/safe/components/Settings/SafeDetails/index.tsx index c04ed03a6b..2026e3506e 100644 --- a/src/routes/safe/components/Settings/SafeDetails/index.tsx +++ b/src/routes/safe/components/Settings/SafeDetails/index.tsx @@ -1,5 +1,5 @@ import { makeStyles } from '@material-ui/core/styles' -import React, { useEffect } from 'react' +import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { styles } from './style' @@ -30,6 +30,8 @@ import { safeParamAddressFromStateSelector, } from 'src/logic/safe/store/selectors' import { useAnalytics, SAFE_NAVIGATION_EVENT } from 'src/utils/googleAnalytics' +import { fetchMasterCopies, MasterCopy, MasterCopyDeployer } from 'src/logic/contracts/api/masterCopies' +import { getMasterCopyAddressFromProxyAddress } from 'src/logic/contracts/safeContracts' export const SAFE_NAME_INPUT_TEST_ID = 'safe-name-input' export const SAFE_NAME_SUBMIT_BTN_TEST_ID = 'change-safe-name-btn' @@ -49,6 +51,7 @@ const SafeDetails = (): React.ReactElement => { const [isModalOpen, setModalOpen] = React.useState(false) const safeAddress = useSelector(safeParamAddressFromStateSelector) + const [safeInfo, setSafeInfo] = useState() const toggleModal = () => { setModalOpen((prevOpen) => !prevOpen) @@ -65,87 +68,111 @@ const SafeDetails = (): React.ReactElement => { setModalOpen(true) } + const getSafeVersion = () => { + if (!safeInfo) { + return '' + } + return safeInfo.deployer === MasterCopyDeployer.GNOSIS + ? safeCurrentVersion + : `${safeCurrentVersion}-${safeInfo.deployer}` + } + + const getSafeVersionUpdate = () => { + if (!safeInfo) { + return '' + } + return safeInfo.deployer === MasterCopyDeployer.GNOSIS && safeNeedsUpdate + ? ` (there's a newer version: ${latestMasterContractVersion})` + : '' + } + useEffect(() => { trackEvent({ category: SAFE_NAVIGATION_EVENT, action: 'Settings', label: 'Details' }) }, [trackEvent]) + useEffect(() => { + const getMasterCopyInfo = async () => { + const masterCopies = await fetchMasterCopies() + const masterCopyAddress = await getMasterCopyAddressFromProxyAddress(safeAddress) + const masterCopy = masterCopies?.find((mc) => mc.address === masterCopyAddress) + setSafeInfo(masterCopy) + } + + if (safeAddress) { + getMasterCopyInfo() + } + }, [safeAddress]) + return ( - <> - - {() => ( - <> - - Safe Version + + {() => ( + <> + + Safe Version + + + + {getSafeVersion()} + {getSafeVersionUpdate()} + + + + {safeNeedsUpdate && isUserOwner ? ( - - + - {safeNeedsUpdate && isUserOwner ? ( - - - - - - ) : null} + ) : null} + + + Modify Safe name + + You can change the name of this Safe. This name is only stored locally and never shared with Gnosis or any + third parties. + + + - - Modify Safe name - - You can change the name of this Safe. This name is only stored locally and never shared with Gnosis or - any third parties. - - - - - - - - - - - - - - - )} - - + + + + + + + + + + + )} + ) } From e8c11ce4460a2f4729b194850c3320752f9b2d6b Mon Sep 17 00:00:00 2001 From: nicosampler Date: Fri, 20 Nov 2020 13:49:33 -0300 Subject: [PATCH 05/11] get masterCopy Address from backend --- src/logic/contracts/safeContracts.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/logic/contracts/safeContracts.ts b/src/logic/contracts/safeContracts.ts index 0a6224ad3e..7000c318f9 100644 --- a/src/logic/contracts/safeContracts.ts +++ b/src/logic/contracts/safeContracts.ts @@ -3,7 +3,6 @@ import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe. import memoize from 'lodash.memoize' import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json' import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json' -import IProxySol from '@gnosis.pm/safe-contracts/build/contracts/IProxy.json' import Web3 from 'web3' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' @@ -13,8 +12,8 @@ import { calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransact import { getWeb3, getNetworkIdFrom } from 'src/logic/wallets/getWeb3' import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d' import { GnosisSafeProxyFactory } from 'src/types/contracts/GnosisSafeProxyFactory.d' -import { IProxy } from 'src/types/contracts/IProxy' import { fetchMasterCopies } from './api/masterCopies' +import { getSafeInfo, SafeInfo } from '../safe/utils/safeInformation' export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001' export const MULTI_SEND_ADDRESS = '0x8d29be29923b68abfdd21e541b9374737b49cdad' @@ -58,10 +57,14 @@ const getProxyFactoryContract = memoize( }, ) -export const getMasterCopyAddressFromProxyAddress = async (proxyAddress: string): Promise => { - const web3 = getWeb3() - const proxyInstance = (new web3.eth.Contract(IProxySol.abi as AbiItem[], proxyAddress) as unknown) as IProxy - return proxyInstance.methods.masterCopy().call() +export const getMasterCopyAddressFromProxyAddress = async (proxyAddress: string): Promise => { + const res = await getSafeInfo(proxyAddress) + const masterCopyAddress = (res as SafeInfo)?.masterCopy + if (!masterCopyAddress) { + console.error(`There was not possible to get masterCopy address from proxy ${proxyAddress}.`) + return + } + return masterCopyAddress } export const instantiateSafeContracts = async () => { @@ -149,6 +152,7 @@ export const validateProxy = async (safeAddress: string): Promise => { const code = await web3.eth.getCode(safeAddress) const codeWithoutMetadata = cleanByteCodeMetadata(code) const supportedProxies = [SafeProxy] + for (let i = 0; i < supportedProxies.length; i += 1) { const proxy = supportedProxies[i] const proxyCode = proxy.deployedBytecode From 1ae38ac638364bd6bca62db4ea82b90dbae3a06a Mon Sep 17 00:00:00 2001 From: nicosampler Date: Fri, 20 Nov 2020 15:22:28 -0300 Subject: [PATCH 06/11] fix prettier errors --- src/config/__tests__/config.test.ts | 4 +-- src/config/index.ts | 16 +++++----- .../networks/__tests__/networks.test.ts | 14 +++++---- src/config/networks/energy_web_chain.ts | 2 +- src/config/networks/index.ts | 2 +- src/config/networks/mainnet.ts | 2 +- src/config/networks/network.d.ts | 30 ++++++++++--------- src/config/networks/xdai.ts | 7 ++--- src/logic/contracts/generateBatchRequests.ts | 20 +++++++++---- src/logic/contracts/historicProxyCode.ts | 2 +- src/logic/contracts/methodIds.ts | 10 ++----- 11 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/config/__tests__/config.test.ts b/src/config/__tests__/config.test.ts index 021a4a20e7..e9a6ef40b2 100644 --- a/src/config/__tests__/config.test.ts +++ b/src/config/__tests__/config.test.ts @@ -80,7 +80,7 @@ describe('Config Services', () => { jest.mock('src/utils/constants', () => ({ NODE_ENV: 'production', NETWORK: 'MAINNET', - APP_ENV: 'production' + APP_ENV: 'production', })) const { getTxServiceUrl, getGnosisSafeAppsUrl } = require('src/config') const TX_SERVICE_URL = mainnet.environment.production.txServiceUrl @@ -100,7 +100,7 @@ describe('Config Services', () => { jest.mock('src/utils/constants', () => ({ NODE_ENV: 'production', NETWORK: 'XDAI', - APP_ENV: 'production' + APP_ENV: 'production', })) const { getTxServiceUrl, getGnosisSafeAppsUrl } = require('src/config') const TX_SERVICE_URL = xdai.environment.production.txServiceUrl diff --git a/src/config/index.ts b/src/config/index.ts index 5dd3dcd6e2..d86606030e 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -32,9 +32,9 @@ const getCurrentEnvironment = (): string => { } type NetworkSpecificConfiguration = EnvironmentSettings & { - network: NetworkSettings, - disabledFeatures?: SafeFeatures, - disabledWallets?: Wallets, + network: NetworkSettings + disabledFeatures?: SafeFeatures + disabledWallets?: Wallets } const configuration = (): NetworkSpecificConfiguration => { @@ -60,7 +60,7 @@ const configuration = (): NetworkSpecificConfiguration => { ...networkBaseConfig, network: configFile.network, disabledFeatures: configFile.disabledFeatures, - disabledWallets: configFile.disabledWallets + disabledWallets: configFile.disabledWallets, } } @@ -137,10 +137,10 @@ const fetchContractABI = memoize( (url, contractAddress) => `${url}_${contractAddress}`, ) -const getNetworkExplorerApiKey = (networkExplorerName: string): string | undefined=> { +const getNetworkExplorerApiKey = (networkExplorerName: string): string | undefined => { switch (networkExplorerName.toLowerCase()) { case 'etherscan': { - return ETHERSCAN_API_KEY + return ETHERSCAN_API_KEY } default: { return undefined @@ -148,7 +148,7 @@ const getNetworkExplorerApiKey = (networkExplorerName: string): string | undefin } } -export const getContractABI = async (contractAddress: string) =>{ +export const getContractABI = async (contractAddress: string) => { const { apiUrl, name } = getNetworkExplorerInfo() const apiKey = getNetworkExplorerApiKey(name) @@ -181,7 +181,7 @@ export const getExplorerInfo = (hash: string): BlockScanInfo => { const type = hash.length > 42 ? 'tx' : 'address' return () => ({ url: `${url}/${type}/${hash}`, - alt: name || '', + alt: name || '', }) } } diff --git a/src/config/networks/__tests__/networks.test.ts b/src/config/networks/__tests__/networks.test.ts index 00a79dfdf0..6cdc086131 100644 --- a/src/config/networks/__tests__/networks.test.ts +++ b/src/config/networks/__tests__/networks.test.ts @@ -41,11 +41,10 @@ describe('Networks config files test', () => { return } - const environmentConfigKeys = Object - .keys(networkConfigElement) - .filter((environmentConfigKey) => - environmentConfigKey.endsWith('Uri') && !!networkConfigElement[environmentConfigKey] - ) + const environmentConfigKeys = Object.keys(networkConfigElement).filter( + (environmentConfigKey) => + environmentConfigKey.endsWith('Uri') && !!networkConfigElement[environmentConfigKey], + ) // Then environmentConfigKeys.forEach((environmentConfigKey) => { @@ -53,7 +52,10 @@ describe('Networks config files test', () => { const isValid = isValidURL(networkConfigElementUri) if (!isValid) { - console.log(`Invalid URI in "${networkFileName}" at ${environment}.${environmentConfigKey}:`, networkConfigElementUri) + console.log( + `Invalid URI in "${networkFileName}" at ${environment}.${environmentConfigKey}:`, + networkConfigElementUri, + ) } expect(isValid).toBeTruthy() diff --git a/src/config/networks/energy_web_chain.ts b/src/config/networks/energy_web_chain.ts index 7253be5bc3..df13c013ae 100644 --- a/src/config/networks/energy_web_chain.ts +++ b/src/config/networks/energy_web_chain.ts @@ -60,7 +60,7 @@ const mainnet: NetworkConfig = { WALLETS.WALLET_LINK, WALLETS.AUTHEREUM, WALLETS.LATTICE, - ] + ], } export default mainnet diff --git a/src/config/networks/index.ts b/src/config/networks/index.ts index 682b33d3ed..03ef405b11 100644 --- a/src/config/networks/index.ts +++ b/src/config/networks/index.ts @@ -11,5 +11,5 @@ export default { rinkeby, xdai, energy_web_chain, - volta + volta, } diff --git a/src/config/networks/mainnet.ts b/src/config/networks/mainnet.ts index 0a7ca3a44d..5aea9a6171 100644 --- a/src/config/networks/mainnet.ts +++ b/src/config/networks/mainnet.ts @@ -42,7 +42,7 @@ const mainnet: NetworkConfig = { decimals: 18, logoUri: EtherLogo, }, - } + }, } export default mainnet diff --git a/src/config/networks/network.d.ts b/src/config/networks/network.d.ts index fed876bb18..2cd2f1a740 100644 --- a/src/config/networks/network.d.ts +++ b/src/config/networks/network.d.ts @@ -51,12 +51,12 @@ export enum ETHEREUM_NETWORK { export type NetworkSettings = { // TODO: id now seems to be unnecessary - id: ETHEREUM_NETWORK, - backgroundColor: string, - textColor: string, - label: string, - isTestNet: boolean, - nativeCoin: Token, + id: ETHEREUM_NETWORK + backgroundColor: string + textColor: string + label: string + isTestNet: boolean + nativeCoin: Token } // something around this to display or not some critical sections in the app, depending on the network support @@ -73,14 +73,16 @@ export type GasPriceOracle = { gasParameter: string } -type GasPrice = { - gasPrice: number - gasPriceOracle?: GasPriceOracle -} | { - gasPrice?: number - // for infura there's a REST API Token required stored in: `REACT_APP_INFURA_TOKEN` - gasPriceOracle: GasPriceOracle -} +type GasPrice = + | { + gasPrice: number + gasPriceOracle?: GasPriceOracle + } + | { + gasPrice?: number + // for infura there's a REST API Token required stored in: `REACT_APP_INFURA_TOKEN` + gasPriceOracle: GasPriceOracle + } export type EnvironmentSettings = GasPrice & { txServiceUrl: string diff --git a/src/config/networks/xdai.ts b/src/config/networks/xdai.ts index b6aa7b2496..743f85fe43 100644 --- a/src/config/networks/xdai.ts +++ b/src/config/networks/xdai.ts @@ -14,12 +14,11 @@ const baseConfig: EnvironmentSettings = { const xDai: NetworkConfig = { environment: { staging: { - ...baseConfig + ...baseConfig, }, production: { ...baseConfig, safeAppsUrl: 'https://apps-xdai.gnosis-safe.io', - }, }, network: { @@ -52,9 +51,7 @@ const xDai: NetworkConfig = { WALLETS.AUTHEREUM, WALLETS.LATTICE, ], - disabledFeatures: [ - FEATURES.ENS_LOOKUP, - ], + disabledFeatures: [FEATURES.ENS_LOOKUP], } export default xDai diff --git a/src/logic/contracts/generateBatchRequests.ts b/src/logic/contracts/generateBatchRequests.ts index adf327b84f..6a724f98c6 100644 --- a/src/logic/contracts/generateBatchRequests.ts +++ b/src/logic/contracts/generateBatchRequests.ts @@ -14,25 +14,33 @@ import { AbiItem } from 'web3-utils' */ type MethodsArgsType = Array - interface Props { +interface Props { abi: AbiItem[] address: string batch?: BatchRequest context?: unknown - methods: Array - } + methods: Array +} -const generateBatchRequests = ({ abi, address, batch, context, methods }: Props): Promise => { +const generateBatchRequests = ({ + abi, + address, + batch, + context, + methods, +}: Props): Promise => { const contractInstance = new web3.eth.Contract(abi, address) const localBatch = new web3.BatchRequest() const values = methods.map((methodObject) => { - let method, type, args: MethodsArgsType = [] + let method, + type, + args: MethodsArgsType = [] if (typeof methodObject === 'string') { method = methodObject } else { - ({ method, type, args } = methodObject) + ;({ method, type, args } = methodObject) } return new Promise((resolve) => { diff --git a/src/logic/contracts/historicProxyCode.ts b/src/logic/contracts/historicProxyCode.ts index 90e08fdc61..b2ebeee791 100644 --- a/src/logic/contracts/historicProxyCode.ts +++ b/src/logic/contracts/historicProxyCode.ts @@ -1,4 +1,4 @@ -// +// // Code of the safe v1.0.0 const proxyCodeV10 = diff --git a/src/logic/contracts/methodIds.ts b/src/logic/contracts/methodIds.ts index c91db228f6..6a06e4bf9b 100644 --- a/src/logic/contracts/methodIds.ts +++ b/src/logic/contracts/methodIds.ts @@ -46,9 +46,7 @@ export const decodeParamsFromSafeMethod = (data: string): DataDecoded | null => const decodedParameters = web3.eth.abi.decodeParameters(['uint'], params) return { method: METHOD_TO_ID[methodId], - parameters: [ - { name: '_threshold', type: 'uint', value: decodedParameters[0] }, - ], + parameters: [{ name: '_threshold', type: 'uint', value: decodedParameters[0] }], } } @@ -57,9 +55,7 @@ export const decodeParamsFromSafeMethod = (data: string): DataDecoded | null => const decodedParameters = web3.eth.abi.decodeParameters(['address'], params) return { method: METHOD_TO_ID[methodId], - parameters: [ - { name: 'module', type: 'address', value: decodedParameters[0] }, - ], + parameters: [{ name: 'module', type: 'address', value: decodedParameters[0] }], } } @@ -85,7 +81,7 @@ const isSafeMethod = (methodId: string): boolean => { } export const decodeMethods = (data: string): DataDecoded | null => { - if(!data.length) { + if (!data.length) { return null } From 8a40e2b2b7894a0205961d30de28a118f95cc740 Mon Sep 17 00:00:00 2001 From: nicosampler Date: Fri, 20 Nov 2020 15:37:50 -0300 Subject: [PATCH 07/11] fix #1558 --- src/logic/contracts/safeContracts.ts | 35 +------------------ .../load/components/DetailsForm/index.tsx | 21 +++++------ 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/src/logic/contracts/safeContracts.ts b/src/logic/contracts/safeContracts.ts index 7000c318f9..d588eb606f 100644 --- a/src/logic/contracts/safeContracts.ts +++ b/src/logic/contracts/safeContracts.ts @@ -2,18 +2,15 @@ import { AbiItem } from 'web3-utils' import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json' import memoize from 'lodash.memoize' import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json' -import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json' import Web3 from 'web3' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' -import { isProxyCode } from 'src/logic/contracts/historicProxyCode' import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' import { calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransactions' import { getWeb3, getNetworkIdFrom } from 'src/logic/wallets/getWeb3' import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d' import { GnosisSafeProxyFactory } from 'src/types/contracts/GnosisSafeProxyFactory.d' -import { fetchMasterCopies } from './api/masterCopies' -import { getSafeInfo, SafeInfo } from '../safe/utils/safeInformation' +import { getSafeInfo, SafeInfo } from 'src/logic/safe/utils/safeInformation' export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001' export const MULTI_SEND_ADDRESS = '0x8d29be29923b68abfdd21e541b9374737b49cdad' @@ -134,33 +131,3 @@ export const getGnosisSafeInstanceAt = (safeAddress: string): GnosisSafe => { const web3 = getWeb3() return (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown) as GnosisSafe } - -export const isMasterCopyValid = async (safeAddress: string): Promise => { - const masterCopyAddress = await getMasterCopyAddressFromProxyAddress(safeAddress) - const res = await fetchMasterCopies() - return !res ? false : res.some((mc) => mc.address === masterCopyAddress) -} - -const cleanByteCodeMetadata = (bytecode: string): string => { - const metaData = 'a165' - return bytecode.substring(0, bytecode.lastIndexOf(metaData)) -} - -export const validateProxy = async (safeAddress: string): Promise => { - // https://solidity.readthedocs.io/en/latest/metadata.html#usage-for-source-code-verification - const web3 = getWeb3() - const code = await web3.eth.getCode(safeAddress) - const codeWithoutMetadata = cleanByteCodeMetadata(code) - const supportedProxies = [SafeProxy] - - for (let i = 0; i < supportedProxies.length; i += 1) { - const proxy = supportedProxies[i] - const proxyCode = proxy.deployedBytecode - const proxyCodeWithoutMetadata = cleanByteCodeMetadata(proxyCode) - if (codeWithoutMetadata === proxyCodeWithoutMetadata) { - return true - } - } - - return isProxyCode(codeWithoutMetadata) -} diff --git a/src/routes/load/components/DetailsForm/index.tsx b/src/routes/load/components/DetailsForm/index.tsx index d5f118c7d5..799d1c95d8 100644 --- a/src/routes/load/components/DetailsForm/index.tsx +++ b/src/routes/load/components/DetailsForm/index.tsx @@ -20,9 +20,9 @@ import { import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' import Paragraph from 'src/components/layout/Paragraph' -import { isMasterCopyValid, validateProxy } from 'src/logic/contracts/safeContracts' import { FIELD_LOAD_ADDRESS, FIELD_LOAD_NAME } from 'src/routes/load/components/fields' import { secondary } from 'src/theme/variables' +import { getSafeInfo } from 'src/logic/safe/utils/safeInformation' const useStyles = makeStyles({ root: { @@ -41,28 +41,23 @@ const useStyles = makeStyles({ }, }) -export const SAFE_INSTANCE_ERROR = 'Address given is not a Safe instance' -export const SAFE_MASTERCOPY_ERROR = 'Address is not a Safe or mastercopy is not supported' +export const SAFE_ADDRESS_NOT_VALID = 'Address given is not a valid Safe address' // In case of an error here, it will be swallowed by final-form // So if you're experiencing any strang behaviours like freeze or hanging // Don't mind to check if everything is OK inside this function :) export const safeFieldsValidation = async (values): Promise> => { const errors = {} - const safeAddress = values[FIELD_LOAD_ADDRESS] + const address = values[FIELD_LOAD_ADDRESS] - if (!safeAddress || mustBeEthereumAddress(safeAddress) !== undefined) { + if (!address || mustBeEthereumAddress(address) !== undefined) { return errors } - const isValidProxy = await validateProxy(safeAddress) - if (!isValidProxy) { - errors[FIELD_LOAD_ADDRESS] = SAFE_INSTANCE_ERROR - return errors - } - - if (!(await isMasterCopyValid(safeAddress))) { - errors[FIELD_LOAD_ADDRESS] = SAFE_MASTERCOPY_ERROR + // if getSafeInfo does not provide data, it's not a valid safe. + const safeInfo = await getSafeInfo(address) + if (!safeInfo) { + errors[FIELD_LOAD_ADDRESS] = SAFE_ADDRESS_NOT_VALID } return errors From 311db32cb916276f9e8dd2f5d9c62c37a0968489 Mon Sep 17 00:00:00 2001 From: nicosampler Date: Tue, 24 Nov 2020 10:00:45 -0300 Subject: [PATCH 08/11] ignore types contracts --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 6684fd0bd5..5660707c45 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,4 +9,5 @@ node_modules public scripts src/assets +src/types/contracts test \ No newline at end of file From ea8a99db52632667309cde3a05814efc03e45ff7 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Wed, 25 Nov 2020 20:16:39 +0100 Subject: [PATCH 09/11] Fix Circles typo --- src/logic/contracts/api/masterCopies.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/contracts/api/masterCopies.ts b/src/logic/contracts/api/masterCopies.ts index b6847d5b70..528de6e3e6 100644 --- a/src/logic/contracts/api/masterCopies.ts +++ b/src/logic/contracts/api/masterCopies.ts @@ -4,7 +4,7 @@ import memoize from 'lodash.memoize' export enum MasterCopyDeployer { GNOSIS = 'Gnosis', - CIRCLE = 'Circle', + CIRCLES = 'Circles', } type MasterCopyFetch = { @@ -25,7 +25,7 @@ const extractMasterCopyInfo = (mc: MasterCopyFetch): MasterCopy => { const masterCopy = { address: mc.address, version: dashIndex === -1 ? mc.version : mc.version.substring(0, dashIndex), - deployer: dashIndex === -1 ? MasterCopyDeployer.GNOSIS : MasterCopyDeployer.CIRCLE, + deployer: dashIndex === -1 ? MasterCopyDeployer.GNOSIS : MasterCopyDeployer.CIRCLES, deployerRepoUrl: dashIndex === -1 ? 'https://github.com/gnosis/safe-contracts/releases' From 8c761ae5c7c509b9adc763379e27aac8b83039ce Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Wed, 25 Nov 2020 20:23:29 +0100 Subject: [PATCH 10/11] Change Circles detect logic --- src/logic/contracts/api/masterCopies.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/logic/contracts/api/masterCopies.ts b/src/logic/contracts/api/masterCopies.ts index 528de6e3e6..0890911e9e 100644 --- a/src/logic/contracts/api/masterCopies.ts +++ b/src/logic/contracts/api/masterCopies.ts @@ -20,16 +20,16 @@ export type MasterCopy = { } const extractMasterCopyInfo = (mc: MasterCopyFetch): MasterCopy => { + const isCircles = mc.version.toLowerCase().includes(MasterCopyDeployer.CIRCLES.toLowerCase()) const dashIndex = mc.version.indexOf('-') const masterCopy = { address: mc.address, - version: dashIndex === -1 ? mc.version : mc.version.substring(0, dashIndex), - deployer: dashIndex === -1 ? MasterCopyDeployer.GNOSIS : MasterCopyDeployer.CIRCLES, - deployerRepoUrl: - dashIndex === -1 - ? 'https://github.com/gnosis/safe-contracts/releases' - : 'https://github.com/CirclesUBI/safe-contracts/releases', + version: !isCircles ? mc.version : mc.version.substring(0, dashIndex), + deployer: !isCircles ? MasterCopyDeployer.GNOSIS : MasterCopyDeployer.CIRCLES, + deployerRepoUrl: !isCircles + ? 'https://github.com/gnosis/safe-contracts/releases' + : 'https://github.com/CirclesUBI/safe-contracts/releases', } return masterCopy } From 35a434886dc0bcbc684abab31da95395ce096112 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Thu, 26 Nov 2020 17:44:04 +0100 Subject: [PATCH 11/11] Use sameAddress to compare mastercopy addresses --- src/routes/safe/components/Settings/SafeDetails/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Settings/SafeDetails/index.tsx b/src/routes/safe/components/Settings/SafeDetails/index.tsx index 2026e3506e..d071c122ab 100644 --- a/src/routes/safe/components/Settings/SafeDetails/index.tsx +++ b/src/routes/safe/components/Settings/SafeDetails/index.tsx @@ -17,6 +17,7 @@ import Paragraph from 'src/components/layout/Paragraph' import Row from 'src/components/layout/Row' import enqueueSnackbar from 'src/logic/notifications/store/actions/enqueueSnackbar' 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 { grantedSelector } from 'src/routes/safe/container/selector' @@ -94,7 +95,7 @@ const SafeDetails = (): React.ReactElement => { const getMasterCopyInfo = async () => { const masterCopies = await fetchMasterCopies() const masterCopyAddress = await getMasterCopyAddressFromProxyAddress(safeAddress) - const masterCopy = masterCopies?.find((mc) => mc.address === masterCopyAddress) + const masterCopy = masterCopies?.find((mc) => sameAddress(mc.address, masterCopyAddress)) setSafeInfo(masterCopy) }