{story()}
diff --git a/src/components/Header/component/CircleDot.jsx b/src/components/Header/component/CircleDot.jsx
index 32ff7f54..7c54d1e2 100644
--- a/src/components/Header/component/CircleDot.jsx
+++ b/src/components/Header/component/CircleDot.jsx
@@ -77,7 +77,7 @@ const KeyRing = ({
const img = isWarning ? triangle : key
return (
-
+ <>
{!hideDot && }
-
+ >
)
}
diff --git a/src/components/Header/component/Layout.stories.js b/src/components/Header/component/Layout.stories.js
index 7d0ccbe3..e8b235b7 100644
--- a/src/components/Header/component/Layout.stories.js
+++ b/src/components/Header/component/Layout.stories.js
@@ -8,7 +8,7 @@ import UserDetails from './ProviderDetails/UserDetails'
import ProviderDisconnected from './ProviderInfo/ProviderDisconnected'
import ConnectDetails from './ProviderDetails/ConnectDetails'
-const FrameDecorator = story =>
{story()}
+const FrameDecorator = (story) =>
{story()}
storiesOf('Components /Header', module)
.addDecorator(FrameDecorator)
diff --git a/src/components/Loader/indes.stories.js b/src/components/Loader/indes.stories.js
index f6576f3b..314b33d1 100644
--- a/src/components/Loader/indes.stories.js
+++ b/src/components/Loader/indes.stories.js
@@ -4,7 +4,7 @@ import * as React from 'react'
import styles from '~/components/layout/PageFrame/index.scss'
import Component from './index'
-const FrameDecorator = story =>
{story()}
+const FrameDecorator = (story) =>
{story()}
storiesOf('Components', module)
.addDecorator(FrameDecorator)
diff --git a/src/components/Stepper/Controls/index.jsx b/src/components/Stepper/Controls/index.jsx
index 0a77d573..ef03c501 100644
--- a/src/components/Stepper/Controls/index.jsx
+++ b/src/components/Stepper/Controls/index.jsx
@@ -26,24 +26,34 @@ type Props = {
lastPage: boolean,
disabled: boolean,
penultimate: boolean,
+ currentStep?: number,
+ buttonLabels?: Array
,
}
const Controls = ({
- onPrevious, firstPage, penultimate, lastPage, disabled,
+ onPrevious,
+ firstPage,
+ penultimate,
+ lastPage,
+ disabled,
+ currentStep,
+ buttonLabels,
}: Props) => {
- // eslint-disable-next-line
- const next = firstPage ? 'Start' : penultimate ? 'Review' : lastPage ? 'Submit' : 'Next'
const back = firstPage ? 'Cancel' : 'Back'
+ let next
+ if (!buttonLabels) {
+ // eslint-disable-next-line
+ next = firstPage ? 'Start' : penultimate ? 'Review' : lastPage ? 'Submit' : 'Next'
+ } else {
+ // $FlowFixMe
+ next = buttonLabels[currentStep]
+ }
+
return (
-
diff --git a/src/routes/load/components/ReviewInformation/index.jsx b/src/routes/load/components/ReviewInformation/index.jsx
index 940586a3..72617944 100644
--- a/src/routes/load/components/ReviewInformation/index.jsx
+++ b/src/routes/load/components/ReviewInformation/index.jsx
@@ -2,29 +2,23 @@
import * as React from 'react'
import classNames from 'classnames'
import { withStyles } from '@material-ui/core/styles'
-import OpenInNew from '@material-ui/icons/OpenInNew'
import Block from '~/components/layout/Block'
import Identicon from '~/components/Identicon'
import OpenPaper from '~/components/Stepper/OpenPaper'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
-import Link from '~/components/layout/Link'
+import EtherscanBtn from '~/components/EtherscanBtn'
import Paragraph from '~/components/layout/Paragraph'
+import CopyBtn from '~/components/CopyBtn'
import Hairline from '~/components/layout/Hairline'
import {
- xs, sm, lg, border, secondary,
+ xs, sm, lg, border,
} from '~/theme/variables'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import { getOwnerNameBy, getOwnerAddressBy, getNumOwnersFrom } from '~/routes/open/components/fields'
-import { getEtherScanLink } from '~/logic/wallets/getWeb3'
import { FIELD_LOAD_NAME, FIELD_LOAD_ADDRESS, THRESHOLD } from '~/routes/load/components/fields'
-const openIconStyle = {
- height: '16px',
- color: secondary,
-}
-
const styles = () => ({
root: {
minHeight: '300px',
@@ -51,6 +45,9 @@ const styles = () => ({
},
user: {
justifyContent: 'left',
+ '& > p': {
+ marginRight: sm,
+ },
},
open: {
paddingLeft: sm,
@@ -65,15 +62,12 @@ const styles = () => ({
},
address: {
paddingLeft: '6px',
+ marginRight: sm,
},
})
-type LayoutProps = {
- network: string,
+type Props = {
userAddress: string,
-}
-
-type Props = LayoutProps & {
values: Object,
classes: Object,
}
@@ -97,9 +91,7 @@ const checkUserAddressOwner = (values: Object, userAddress: string): boolean =>
class ReviewComponent extends React.PureComponent {
render() {
- const {
- values, classes, network, userAddress,
- } = this.props
+ const { values, classes, userAddress } = this.props
const isOwner = checkUserAddressOwner(values, userAddress)
const owners = getAccountsFrom(values)
@@ -132,9 +124,8 @@ class ReviewComponent extends React.PureComponent {
{shortVersionOf(safeAddress, 4)}
-
-
-
+
+
@@ -177,13 +168,8 @@ class ReviewComponent extends React.PureComponent {
{address}
-
-
-
+
+
diff --git a/src/routes/open/components/Layout.jsx b/src/routes/open/components/Layout.jsx
index 0e6a30e5..75fe9fba 100644
--- a/src/routes/open/components/Layout.jsx
+++ b/src/routes/open/components/Layout.jsx
@@ -13,10 +13,10 @@ import { getOwnerNameBy, getOwnerAddressBy, FIELD_CONFIRMATIONS } from '~/routes
import { history } from '~/store'
import { secondary } from '~/theme/variables'
-const getSteps = () => ['Start', 'Owners and confirmations', 'Review']
+const getSteps = () => ['Name', 'Owners and confirmations', 'Review']
const initialValuesFrom = (userAccount: string) => ({
- [getOwnerNameBy(0)]: 'My Metamask (me)',
+ [getOwnerNameBy(0)]: 'My Wallet',
[getOwnerAddressBy(0)]: userAccount,
[FIELD_CONFIRMATIONS]: '1',
})
@@ -69,7 +69,9 @@ const Layout = ({
>
{SafeNameField}
{SafeOwnersFields}
- {Review}
+
+ {Review}
+
) : (
diff --git a/src/routes/open/components/Layout.stories.js b/src/routes/open/components/Layout.stories.js
index 98f4a541..08606dc3 100644
--- a/src/routes/open/components/Layout.stories.js
+++ b/src/routes/open/components/Layout.stories.js
@@ -8,7 +8,7 @@ import { getProviderInfo } from '~/logic/wallets/getWeb3'
import { sleep } from '~/utils/timer'
import Component from './Layout'
-const FrameDecorator = story => {story()}
+const FrameDecorator = (story) => {story()}
const store = new Store({
safeAddress: '',
diff --git a/src/routes/open/components/ReviewInformation/index.jsx b/src/routes/open/components/ReviewInformation/index.jsx
index 056e72c0..296cea50 100644
--- a/src/routes/open/components/ReviewInformation/index.jsx
+++ b/src/routes/open/components/ReviewInformation/index.jsx
@@ -2,26 +2,24 @@
import * as React from 'react'
import classNames from 'classnames'
import { withStyles } from '@material-ui/core/styles'
-import OpenInNew from '@material-ui/icons/OpenInNew'
+import { estimateGasForDeployingSafe } from '~/logic/contracts/safeContracts'
import { getNamesFrom, getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import Block from '~/components/layout/Block'
+import EtherscanBtn from '~/components/EtherscanBtn'
+import CopyBtn from '~/components/CopyBtn'
import Identicon from '~/components/Identicon'
import OpenPaper from '~/components/Stepper/OpenPaper'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
-import Link from '~/components/layout/Link'
import Paragraph from '~/components/layout/Paragraph'
import {
- sm, md, lg, border, secondary, background,
+ sm, md, lg, border, background,
} from '~/theme/variables'
import Hairline from '~/components/layout/Hairline'
-import { getEtherScanLink } from '~/logic/wallets/getWeb3'
+import { getWeb3 } from '~/logic/wallets/getWeb3'
import { FIELD_NAME, FIELD_CONFIRMATIONS, getNumOwnersFrom } from '../fields'
-const openIconStyle = {
- height: '16px',
- color: secondary,
-}
+const { useEffect, useState } = React
const styles = () => ({
root: {
@@ -55,6 +53,9 @@ const styles = () => ({
},
user: {
justifyContent: 'left',
+ '& > p': {
+ marginRight: sm,
+ },
},
open: {
paddingLeft: sm,
@@ -65,22 +66,40 @@ const styles = () => ({
},
})
-type LayoutProps = {
- network: string,
-}
-
-type Props = LayoutProps & {
+type Props = {
values: Object,
classes: Object,
+ userAccount: string,
}
-const ReviewComponent = ({ values, classes, network }: Props) => {
+const ReviewComponent = ({ values, classes, userAccount }: Props) => {
+ const [gasCosts, setGasCosts] = useState('0.00')
const names = getNamesFrom(values)
const addresses = getAccountsFrom(values)
const numOwners = getNumOwnersFrom(values)
+ useEffect(() => {
+ let isCurrent = true
+ const estimateGas = async () => {
+ const web3 = getWeb3()
+ const { fromWei, toBN } = web3.utils
+ const estimatedGasCosts = await estimateGasForDeployingSafe(addresses, numOwners, userAccount)
+ const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether')
+ const roundedGasCosts = parseFloat(gasCostsAsEth).toFixed(3)
+ if (isCurrent) {
+ setGasCosts(roundedGasCosts)
+ }
+ }
+
+ estimateGas()
+
+ return () => {
+ isCurrent = false
+ }
+ }, [])
+
return (
-
+ <>
@@ -129,13 +148,8 @@ const ReviewComponent = ({ values, classes, network }: Props) => {
{addresses[index]}
-
-
-
+
+
@@ -148,21 +162,26 @@ const ReviewComponent = ({ values, classes, network }: Props) => {
You're about to create a new Safe and will have to confirm a transaction with your currently connected
- wallet. Make sure you have ETH in this wallet to fund this transaction.
+ wallet. The creation will cost approximately
+ {' '}
+ {gasCosts}
+ {' '}
+ ETH. The exact amount will be determined by your
+ wallet.
-
+ >
)
}
const ReviewPage = withStyles(styles)(ReviewComponent)
-const Review = ({ network }: LayoutProps) => (controls: React.Node, { values }: Object) => (
-
+const Review = () => (controls: React.Node, { values }: Object) => (
+ <>
-
+
-
+ >
)
export default Review
diff --git a/src/routes/open/components/SafeNameForm/index.jsx b/src/routes/open/components/SafeNameForm/index.jsx
index aade39f6..203d557c 100644
--- a/src/routes/open/components/SafeNameForm/index.jsx
+++ b/src/routes/open/components/SafeNameForm/index.jsx
@@ -33,7 +33,7 @@ const styles = () => ({
})
const SafeName = ({ classes }: Props) => (
-
+ <>
You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new wallet
@@ -67,13 +67,13 @@ const SafeName = ({ classes }: Props) => (
Ethereum blockchain. These funds cannot be accessed by Gnosis at any point.
-
+ >
)
const SafeNameForm = withStyles(styles)(SafeName)
const SafeNamePage = () => (controls: React.Node) => (
-
+
)
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx
index 126c94cc..54b6ac95 100644
--- a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx
@@ -109,7 +109,13 @@ const SafeOwners = (props: Props) => {
<>
- Specify the owners of the Safe.
+ Your Safe will have one or more owners. We have prefilled the first owner with your connected wallet details,
+ but you are free to change this to a different owner.
+
+
+ Add additional owners (e.g. wallets of your teammates) and specify how many of them have to confirm a
+ transaction before it gets executed. In general, the more confirmations required, the more secure is your
+ Safe.
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js b/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js
index e4697f0e..f32d20c0 100644
--- a/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js
@@ -1,7 +1,5 @@
// @flow
-import {
- uniqueAddress,
-} from '~/components/forms/validator'
+import { uniqueAddress } from '~/components/forms/validator'
export const getAddressValidator = (addresses: string[], position: number) => {
// thanks Rich Harris
diff --git a/src/routes/open/components/fields.js b/src/routes/open/components/fields.js
index fa280c90..a786ec73 100644
--- a/src/routes/open/components/fields.js
+++ b/src/routes/open/components/fields.js
@@ -9,7 +9,7 @@ export const getOwnerAddressBy = (index: number) => `owner${index}Address`
export const getNumOwnersFrom = (values: Object) => {
const accounts = Object.keys(values)
.sort()
- .filter(key => /^owner\d+Address$/.test(key) && !!values[key])
+ .filter((key) => /^owner\d+Address$/.test(key) && !!values[key])
return accounts.length
}
diff --git a/src/routes/open/container/Open.jsx b/src/routes/open/container/Open.jsx
index ee1b9b0b..1c99006c 100644
--- a/src/routes/open/container/Open.jsx
+++ b/src/routes/open/container/Open.jsx
@@ -59,6 +59,10 @@ export const createSafe = async (values: Object, userAccount: string, addSafe: A
}
class Open extends React.Component {
+ async componentDidMount() {
+ await initContracts()
+ }
+
onCallSafeContractSubmit = async (values) => {
try {
const { userAccount, addSafe } = this.props
diff --git a/src/routes/open/container/selector.js b/src/routes/open/container/selector.js
index 24fb891d..be0e8be9 100644
--- a/src/routes/open/container/selector.js
+++ b/src/routes/open/container/selector.js
@@ -2,7 +2,7 @@
import { createStructuredSelector } from 'reselect'
import { providerNameSelector, userAccountSelector, networkSelector } from '~/logic/wallets/store/selectors'
-export default createStructuredSelector({
+export default createStructuredSelector