Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/components/AddressInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Identicon from 'src/components/Identicon'
import Block from 'src/components/layout/Block'
import Bold from 'src/components/layout/Bold'
import Paragraph from 'src/components/layout/Paragraph'
import { ExplorerTypes } from 'src/logic/wallets/getWeb3'
import { border, xs } from 'src/theme/variables'
import styled from 'styled-components'

Expand Down Expand Up @@ -60,7 +59,7 @@ const AddressInfo = ({ ethBalance, safeAddress, safeName }: Props): React.ReactE
{safeAddress}
</Paragraph>
<CopyBtn content={safeAddress} />
<EtherscanBtn type={ExplorerTypes.Address} value={safeAddress} />
<EtherscanBtn value={safeAddress} />
</div>
{ethBalance && (
<StyledBlock>
Expand Down
3 changes: 1 addition & 2 deletions src/components/App/ReceiveModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import Col from 'src/components/layout/Col'
import Hairline from 'src/components/layout/Hairline'
import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row'
import { ExplorerTypes } from 'src/logic/wallets/getWeb3'
import { lg, md, screenSm, secondaryText, sm } from 'src/theme/variables'
import { copyToClipboard } from 'src/utils/clipboard'

Expand Down Expand Up @@ -116,7 +115,7 @@ const ReceiveModal = ({ onClose, safeAddress, safeName }: Props) => {
{safeAddress}
</Paragraph>
<CopyBtn content={safeAddress} />
<EtherscanBtn type={ExplorerTypes.Address} value={safeAddress} />
<EtherscanBtn value={safeAddress} />
</Block>
</Col>
<Hairline />
Expand Down
9 changes: 5 additions & 4 deletions src/components/ConnectButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import React from 'react'

import Button from 'src/components/layout/Button'
import { getNetworkId } from 'src/config'
import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
import { getWeb3, setWeb3 } from 'src/logic/wallets/getWeb3'
import { fetchProvider } from 'src/logic/wallets/store/actions'
import transactionDataCheck from 'src/logic/wallets/transactionDataCheck'
import { getSupportedWallets } from 'src/logic/wallets/utils/walletList'
import { store } from 'src/store'
import { BLOCKNATIVE_KEY } from 'src/utils/constants'

const isMainnet = process.env.REACT_APP_NETWORK === 'mainnet'

const BLOCKNATIVE_API_KEY = isMainnet ? process.env.REACT_APP_BLOCKNATIVE_KEY : '7fbb9cee-7e97-4436-8770-8b29a9a8814c'
const networkId = getNetworkId()
const BLOCKNATIVE_API_KEY = BLOCKNATIVE_KEY[networkId] ?? BLOCKNATIVE_KEY[ETHEREUM_NETWORK.RINKEBY]

let lastUsedAddress = ''
let providerName
Expand All @@ -20,7 +21,7 @@ const wallets = getSupportedWallets()

export const onboard = Onboard({
dappId: BLOCKNATIVE_API_KEY,
networkId: getNetworkId(),
networkId: networkId,
subscriptions: {
wallet: (wallet) => {
if (wallet.provider) {
Expand Down
15 changes: 6 additions & 9 deletions src/components/EtherscanBtn/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import React from 'react'
import EtherscanOpenIcon from './img/etherscan-open.svg'

import Img from 'src/components/layout/Img'
import { ExplorerTypes, getExplorerLink } from 'src/logic/wallets/getWeb3'
import { xs } from 'src/theme/variables'
import { getExplorerInfo } from 'src/config'

const useStyles = makeStyles({
container: {
Expand All @@ -30,26 +30,23 @@ const useStyles = makeStyles({
interface EtherscanBtnProps {
className?: string
increaseZindex?: boolean
type: ExplorerTypes
value: string
}

const EtherscanBtn = ({
className = '',
increaseZindex = false,
type,
value,
}: EtherscanBtnProps): React.ReactElement => {
const EtherscanBtn = ({ className = '', increaseZindex = false, value }: EtherscanBtnProps): React.ReactElement => {
const classes = useStyles()
const customClasses = increaseZindex ? { popper: classes.increasedPopperZindex } : {}

const explorerInfo = getExplorerInfo(value)
const { url } = explorerInfo()

return (
<Tooltip classes={customClasses} placement="top" title="Show details on Etherscan">
<a
aria-label="Show details on Etherscan"
className={cn(classes.container, className)}
onClick={(event) => event.stopPropagation()}
href={getExplorerLink(type, value)}
href={url}
rel="noopener noreferrer"
target="_blank"
>
Expand Down
6 changes: 2 additions & 4 deletions src/components/EtherscanLink/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { makeStyles } from '@material-ui/core/styles'
import cn from 'classnames'
import React from 'react'
import { ExplorerTypes } from 'src/logic/wallets/getWeb3'

import { styles } from './style'

Expand All @@ -18,11 +17,10 @@ interface EtherscanLinkProps {
className?: string
cut?: number
knownAddress?: boolean
type: ExplorerTypes
value: string
}

const EtherscanLink = ({ className, cut, knownAddress, type, value }: EtherscanLinkProps): React.ReactElement => {
const EtherscanLink = ({ className, cut, knownAddress, value }: EtherscanLinkProps): React.ReactElement => {
const classes = useStyles()

return (
Expand All @@ -31,7 +29,7 @@ const EtherscanLink = ({ className, cut, knownAddress, type, value }: EtherscanL
{cut ? shortVersionOf(value, cut) : value}
</Span>
<CopyBtn className={cn(classes.button, classes.firstButton)} content={value} />
<EtherscanBtn className={classes.button} type={type} value={value} />
<EtherscanBtn className={classes.button} value={value} />
{knownAddress !== undefined ? <EllipsisTransactionDetails address={value} knownAddress={knownAddress} /> : null}
</Block>
)
Expand Down
30 changes: 12 additions & 18 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import networks from 'src/config/networks'
import {
EnvironmentSettings,
ETHEREUM_NETWORK,
NetworkSettings,
SafeFeatures,
} from 'src/config/networks/network.d'
import { checksumAddress } from 'src/utils/checksumAddress'
import { GOOGLE_ANALYTICS_ID, NETWORK, APP_ENV, NODE_ENV, ETHERSCAN_API_KEY } from 'src/utils/constants'
import { EnvironmentSettings, ETHEREUM_NETWORK, NetworkSettings, SafeFeatures } 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 { ensureOnce } from 'src/utils/singleton'
import memoize from 'lodash.memoize'

Expand Down Expand Up @@ -67,7 +61,15 @@ export const getRelayUrl = (): string | undefined => getConfig()?.relayApiUrl

export const getGnosisSafeAppsUrl = (): string => getConfig()?.safeAppsUrl

export const getRpcServiceUrl = (): string => getConfig()?.rpcServiceUrl
export const getRpcServiceUrl = (): string => {
const usesInfuraRPC = [ETHEREUM_NETWORK.MAINNET, ETHEREUM_NETWORK.RINKEBY].includes(getNetworkId())

if (usesInfuraRPC) {
return getConfig()?.rpcServiceUrl + INFURA_TOKEN
}

return getConfig()?.rpcServiceUrl
}

export const getNetworkExplorerInfo = (): { name: string; url: string; apiUrl: string } => ({
name: getConfig()?.networkExplorerName,
Expand All @@ -87,15 +89,7 @@ export const getAllTransactionsUriFrom = (safeAddress: string) => `safes/${safeA

export const getSafeCreationTxUri = (safeAddress: string) => `safes/${safeAddress}/creation/`

export const getGoogleAnalyticsTrackingID = (): string => GOOGLE_ANALYTICS_ID[getNetworkName()]

export const buildSafeCreationTxUrl = (safeAddress: string) => {
const host = getTxServiceUrl()
const address = checksumAddress(safeAddress)
const base = getSafeCreationTxUri(address)

return `${host}${base}`
}
export const getGoogleAnalyticsTrackingID = (): string => GOOGLE_ANALYTICS_ID[getNetworkId()]

const fetchContractABI = memoize(
async (url: string, contractAddress: string, apiKey?: string) => {
Expand Down
89 changes: 45 additions & 44 deletions src/logic/contracts/safeContracts.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { AbiItem } from 'web3-utils'
import contract from 'truffle-contract'
import Web3 from 'web3'
import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json'
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json'
import { ensureOnce } from 'src/utils/singleton'
import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json'
import memoize from 'lodash.memoize'
import { getWeb3, getNetworkIdFrom } from 'src/logic/wallets/getWeb3'
import { calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransactions'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'

import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
import { isProxyCode } from 'src/logic/contracts/historicProxyCode'
import { GnosisSafeProxyFactory } from 'src/types/contracts/GnosisSafeProxyFactory.d';
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 Web3 from 'web3'
import { AbiItem } from 'web3-utils'

export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001'
export const MULTI_SEND_ADDRESS = '0x8d29be29923b68abfdd21e541b9374737b49cdad'
Expand All @@ -20,24 +20,39 @@ export const DEFAULT_FALLBACK_HANDLER_ADDRESS = '0xd5D82B6aDDc9027B22dCA772Aa68D
export const SAFE_MASTER_COPY_ADDRESS_V10 = '0xb6029EA3B2c51D09a50B53CA8012FeEB05bDa35A'


let proxyFactoryMaster
let safeMaster

const createGnosisSafeContract = (web3: Web3) => {
const gnosisSafe = contract(GnosisSafeSol)
gnosisSafe.setProvider(web3.currentProvider)

return gnosisSafe
let proxyFactoryMaster: GnosisSafeProxyFactory
let safeMaster: GnosisSafe

/**
* Creates a Contract instance of the GnosisSafe contract
* @param {Web3} web3
* @param {ETHEREUM_NETWORK} networkId
*/
const createGnosisSafeContract = (web3: Web3, networkId: ETHEREUM_NETWORK) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be typed to return GnosisSafe ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the returned type is inferred in this case, shall we add it anyway? I truly don't remember.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right, I think it's not needed

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
}

const createProxyFactoryContract = (web3: Web3, networkId: number): GnosisSafeProxyFactory => {
const contractAddress = ProxyFactorySol.networks[networkId].address
const proxyFactory = new web3.eth.Contract(ProxyFactorySol.abi as AbiItem[], contractAddress) as unknown as GnosisSafeProxyFactory

return proxyFactory
/**
* 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
}

export const getGnosisSafeContract = memoize(createGnosisSafeContract)

const getCreateProxyFactoryContract = memoize(createProxyFactoryContract)

const instantiateMasterCopies = async () => {
Expand All @@ -47,25 +62,11 @@ const instantiateMasterCopies = async () => {
// Create ProxyFactory Master Copy
proxyFactoryMaster = getCreateProxyFactoryContract(web3, networkId)

// Initialize Safe master copy
const GnosisSafe = getGnosisSafeContract(web3)
safeMaster = await GnosisSafe.deployed()
}

// ONLY USED IN TEST ENVIRONMENT
const createMasterCopies = async () => {
const web3 = getWeb3()
const accounts = await web3.eth.getAccounts()
const userAccount = accounts[0]

const ProxyFactory = getCreateProxyFactoryContract(web3, 4441)
proxyFactoryMaster = await ProxyFactory.deploy({ data: GnosisSafeSol.bytecode }).send({ from: userAccount, gas: 5000000 })

const GnosisSafe = getGnosisSafeContract(web3)
safeMaster = await GnosisSafe.new({ from: userAccount, gas: '7000000' })
// Create Safe Master copy
safeMaster = getGnosisSafeContract(web3, networkId)
}

export const initContracts = process.env.NODE_ENV === 'test' ? ensureOnce(createMasterCopies) : instantiateMasterCopies
export const initContracts = instantiateMasterCopies

export const getSafeMasterContract = async () => {
await initContracts()
Expand All @@ -74,25 +75,25 @@ export const getSafeMasterContract = async () => {
}

export const getSafeDeploymentTransaction = (safeAccounts, numConfirmations) => {
const gnosisSafeData = safeMaster.contract.methods
const gnosisSafeData = safeMaster.methods
.setup(safeAccounts, numConfirmations, ZERO_ADDRESS, '0x', DEFAULT_FALLBACK_HANDLER_ADDRESS, ZERO_ADDRESS, 0, ZERO_ADDRESS)
.encodeABI()

return proxyFactoryMaster.methods.createProxy(safeMaster.address, gnosisSafeData)
return proxyFactoryMaster.methods.createProxy(safeMaster.options.address, gnosisSafeData)
}

export const estimateGasForDeployingSafe = async (
safeAccounts,
numConfirmations,
userAccount,
) => {
const gnosisSafeData = await safeMaster.contract.methods
const gnosisSafeData = await safeMaster.methods
.setup(safeAccounts, numConfirmations, ZERO_ADDRESS, '0x', DEFAULT_FALLBACK_HANDLER_ADDRESS, ZERO_ADDRESS, 0, ZERO_ADDRESS)
.encodeABI()
const proxyFactoryData = proxyFactoryMaster.methods
.createProxy(safeMaster.address, gnosisSafeData)
.createProxy(safeMaster.options.address, gnosisSafeData)
.encodeABI()
const gas = await calculateGasOf(proxyFactoryData, userAccount, proxyFactoryMaster.address)
const gas = await calculateGasOf(proxyFactoryData, userAccount, proxyFactoryMaster.options.address)
const gasPrice = await calculateGasPrice()

return gas * parseInt(gasPrice, 10)
Expand Down
2 changes: 1 addition & 1 deletion src/logic/safe/store/actions/fetchSafeCreationTx.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios'
import { List } from 'immutable'

import { buildSafeCreationTxUrl } from 'src/config'
import { buildSafeCreationTxUrl } from 'src/logic/safe/utils/buildSafeCreationTxUrl'
import { addOrUpdateTransactions } from './transactions/addOrUpdateTransactions'
import { makeTransaction } from 'src/logic/safe/store/models/transaction'
import { TransactionTypes, TransactionStatus } from 'src/logic/safe/store/models/types/transaction'
Expand Down
10 changes: 10 additions & 0 deletions src/logic/safe/utils/buildSafeCreationTxUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getTxServiceUrl, getSafeCreationTxUri } from 'src/config'
import { checksumAddress } from 'src/utils/checksumAddress'

export const buildSafeCreationTxUrl = (safeAddress: string): string => {
const host = getTxServiceUrl()
const address = checksumAddress(safeAddress)
const base = getSafeCreationTxUri(address)

return `${host}${base}`
}
2 changes: 1 addition & 1 deletion src/logic/safe/utils/safeVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const getCurrentMasterContractLastVersion = async (): Promise<string> =>
const safeMaster = await getSafeMasterContract()
let safeMasterVersion
try {
safeMasterVersion = await safeMaster.VERSION()
safeMasterVersion = await safeMaster.methods.VERSION().call()
} catch (err) {
// Default in case that it's not possible to obtain the version from the contract, returns a hardcoded value or an
// env variable
Expand Down
Loading