- {SafeNameField}
- {SafeOwnersFields}
- {SafeThresholdField}
- {Review}
+
+ {SafeNameField}
+ {SafeOwnersFields}
+ {Review}
) : (
- No metamask detected
+ No web3 provider detected
)}
)
diff --git a/src/routes/open/components/ReviewInformation/index.jsx b/src/routes/open/components/ReviewInformation/index.jsx
index 940ea653..056e72c0 100644
--- a/src/routes/open/components/ReviewInformation/index.jsx
+++ b/src/routes/open/components/ReviewInformation/index.jsx
@@ -129,7 +129,11 @@ const ReviewComponent = ({ values, classes, network }: Props) => {
{addresses[index]}
-
+
@@ -143,10 +147,8 @@ const ReviewComponent = ({ values, classes, network }: Props) => {
- {"You're about to create a new Safe."}
-
-
- Make sure you have enough ETH in your wallet client to fund this transaction.
+ 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.
diff --git a/src/routes/open/components/SafeNameForm/index.jsx b/src/routes/open/components/SafeNameForm/index.jsx
index 055a7894..aade39f6 100644
--- a/src/routes/open/components/SafeNameForm/index.jsx
+++ b/src/routes/open/components/SafeNameForm/index.jsx
@@ -5,7 +5,6 @@ import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import { required } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
-import Row from '~/components/layout/Row'
import { FIELD_NAME } from '~/routes/open/components/fields'
import Paragraph from '~/components/layout/Paragraph'
import OpenPaper from '~/components/Stepper/OpenPaper'
@@ -35,10 +34,25 @@ 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
+ a name. This name is only stored locally and will never be shared with Gnosis or any third parties.
+
+
+
+
+
- This setup will create a Safe with one or more owners. Optionally give the Safe a local name. By continuing you
- consent with the
+ By continuing you consent with the
{' '}
terms of use
@@ -49,35 +63,10 @@ const SafeName = ({ classes }: Props) => (
privacy policy
- .
+ . Most importantly, you confirm that your funds are held securely in the Gnosis Safe, a smart contract on the
+ Ethereum blockchain. These funds cannot be accessed by Gnosis at any point.
-
-
- ●
-
-
- I understand that my funds are held securely in my Safe. They cannot be accessed by Gnosis.
-
-
-
-
- ●
-
-
- My Safe is a smart contract on the Ethereum blockchain.
-
-
-
-
-
)
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/index.jsx b/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/index.jsx
new file mode 100644
index 00000000..80405529
--- /dev/null
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/index.jsx
@@ -0,0 +1,119 @@
+// @flow
+import * as React from 'react'
+import QrReader from 'react-qr-reader'
+import { withStyles } from '@material-ui/core/styles'
+import Close from '@material-ui/icons/Close'
+import IconButton from '@material-ui/core/IconButton'
+import CircularProgress from '@material-ui/core/CircularProgress'
+import Paragraph from '~/components/layout/Paragraph'
+import Button from '~/components/layout/Button'
+import Block from '~/components/layout/Block'
+import Row from '~/components/layout/Row'
+import Hairline from '~/components/layout/Hairline'
+import Col from '~/components/layout/Col'
+import Modal from '~/components/Modal'
+import { checkWebcam } from './utils'
+import { styles } from './style'
+
+const { useEffect, useState } = React
+
+type Props = {
+ onClose: () => void,
+ classes: Object,
+ onScan: Function,
+ isOpen: boolean,
+}
+
+const ScanQRModal = ({
+ classes, onClose, isOpen, onScan,
+}: Props) => {
+ const [hasWebcam, setHasWebcam] = useState(null)
+ const scannerRef: Object = React.createRef()
+ const openImageDialog = () => {
+ scannerRef.current.openImageDialog()
+ }
+
+ useEffect(() => {
+ checkWebcam(
+ () => {
+ setHasWebcam(true)
+ },
+ () => {
+ setHasWebcam(false)
+ },
+ )
+ }, [])
+
+ useEffect(() => {
+ // this fires only when the hasWebcam changes to false (null > false (user doesn't have webcam)
+ // , true > false (user switched from webcam to file upload))
+ // Doesn't fire on re-render
+ if (hasWebcam === false) {
+ openImageDialog()
+ }
+ }, [hasWebcam])
+
+ return (
+
+
+
+ Scan QR
+
+
+
+
+
+
+
+ {hasWebcam === null ? (
+
+
+
+ ) : (
+ {
+ if (data) onScan(data)
+ }}
+ onError={(err) => {
+ console.error(err)
+ }}
+ style={{ width: '400px', height: '400px' }}
+ />
+ )}
+
+
+
+
+
+
+
+ )
+}
+
+export default withStyles(styles)(ScanQRModal)
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/style.js b/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/style.js
new file mode 100644
index 00000000..50d04702
--- /dev/null
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/style.js
@@ -0,0 +1,35 @@
+// @flow
+import { lg, sm, background } from '~/theme/variables'
+
+export const styles = () => ({
+ heading: {
+ padding: `${sm} ${lg}`,
+ justifyContent: 'space-between',
+ maxHeight: '75px',
+ boxSizing: 'border-box',
+ },
+ loaderContainer: {
+ width: '100%',
+ height: '100%',
+ },
+ manage: {
+ fontSize: '24px',
+ },
+ close: {
+ height: '35px',
+ width: '35px',
+ },
+ detailsContainer: {
+ backgroundColor: background,
+ maxHeight: '420px',
+ },
+ buttonRow: {
+ height: '84px',
+ justifyContent: 'center',
+ },
+ button: {
+ '&:last-child': {
+ marginLeft: sm,
+ },
+ },
+})
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/utils.js b/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/utils.js
new file mode 100644
index 00000000..50bdc089
--- /dev/null
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/ScanQRModal/utils.js
@@ -0,0 +1,15 @@
+// @flow
+navigator.getMedia = navigator.getUserMedia // use the proper vendor prefix
+ || navigator.webkitGetUserMedia
+ || navigator.mozGetUserMedia
+ || navigator.msGetUserMedia
+
+export const checkWebcam = (success: Function, err: Function) => navigator.getMedia(
+ { video: true },
+ () => {
+ success()
+ },
+ () => {
+ err()
+ },
+)
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx
new file mode 100644
index 00000000..bd36a6cf
--- /dev/null
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx
@@ -0,0 +1,231 @@
+// @flow
+import * as React from 'react'
+import { withStyles } from '@material-ui/core/styles'
+import InputAdornment from '@material-ui/core/InputAdornment'
+import CheckCircle from '@material-ui/icons/CheckCircle'
+import MenuItem from '@material-ui/core/MenuItem'
+import Field from '~/components/forms/Field'
+import TextField from '~/components/forms/TextField'
+import SelectField from '~/components/forms/SelectField'
+import {
+ required, composeValidators, noErrorsOn, mustBeInteger, minValue,
+} from '~/components/forms/validator'
+import Block from '~/components/layout/Block'
+import Button from '~/components/layout/Button'
+import Row from '~/components/layout/Row'
+import Img from '~/components/layout/Img'
+import Col from '~/components/layout/Col'
+import {
+ FIELD_CONFIRMATIONS,
+ getOwnerNameBy,
+ getOwnerAddressBy,
+ getNumOwnersFrom,
+} from '~/routes/open/components/fields'
+import Paragraph from '~/components/layout/Paragraph'
+import OpenPaper from '~/components/Stepper/OpenPaper'
+import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
+import Hairline from '~/components/layout/Hairline'
+import trash from '~/assets/icons/trash.svg'
+import QRIcon from '~/assets/icons/qrcode.svg'
+import ScanQRModal from './ScanQRModal'
+import { getAddressValidators } from './validators'
+import { styles } from './style'
+
+type Props = {
+ classes: Object,
+ otherAccounts: string[],
+ errors: Object,
+ form: Object,
+ values: Object,
+}
+
+const { useState } = React
+
+export const ADD_OWNER_BUTTON = '+ ADD ANOTHER OWNER'
+
+export const calculateValuesAfterRemoving = (index: number, notRemovedOwners: number, values: Object) => {
+ const initialValues = { ...values }
+
+ const numOwnersAfterRemoving = notRemovedOwners - 1
+ // muevo indices
+ for (let i = index; i < numOwnersAfterRemoving; i += 1) {
+ initialValues[getOwnerNameBy(i)] = values[getOwnerNameBy(i + 1)]
+ initialValues[getOwnerAddressBy(i)] = values[getOwnerAddressBy(i + 1)]
+ }
+
+ if (+values[FIELD_CONFIRMATIONS] === notRemovedOwners) {
+ initialValues[FIELD_CONFIRMATIONS] = numOwnersAfterRemoving.toString()
+ }
+
+ delete initialValues[getOwnerNameBy(index)]
+ delete initialValues[getOwnerAddressBy(index)]
+
+ return initialValues
+}
+
+const SafeOwners = (props: Props) => {
+ const {
+ classes, errors, otherAccounts, values, form,
+ } = props
+
+ const validOwners = getNumOwnersFrom(values)
+ const [numOwners, setNumOwners] = useState(validOwners)
+ const [qrModalOpen, setQrModalOpen] = useState(false)
+ const [scanQrForOwnerName, setScanQrForOwnerName] = useState(null)
+
+ const openQrModal = (ownerName) => {
+ setScanQrForOwnerName(ownerName)
+ setQrModalOpen(true)
+ }
+
+ const closeQrModal = () => {
+ setQrModalOpen(false)
+ }
+
+ const onRemoveRow = (index: number) => () => {
+ const initialValues = calculateValuesAfterRemoving(index, numOwners, values)
+ form.reset(initialValues)
+
+ setNumOwners(numOwners - 1)
+ }
+
+ const onAddOwner = () => {
+ setNumOwners(numOwners + 1)
+ }
+
+ const handleScan = (value) => {
+ let scannedAddress = value
+
+ if (scannedAddress.startsWith('ethereum:')) {
+ scannedAddress = scannedAddress.replace('ethereum:', '')
+ }
+
+ form.mutators.setValue(scanQrForOwnerName, scannedAddress)
+ closeQrModal()
+ }
+
+ return (
+
+
+
+ Specify the owners of the Safe.
+
+
+
+
+ NAME
+ ADDRESS
+
+
+
+ {[...Array(Number(numOwners))].map((x, index) => {
+ const addressName = getOwnerAddressBy(index)
+
+ return (
+
+
+
+
+
+
+
+
+ ),
+ }
+ }
+ type="text"
+ validate={getAddressValidators(otherAccounts, index)}
+ placeholder="Owner Address*"
+ text="Owner Address"
+ />
+
+
+ {
+ openQrModal(addressName)
+ }}
+ />
+
+
+ {index > 0 && }
+
+
+ )
+ })}
+
+
+
+
+
+
+ Any transaction requires the confirmation of:
+
+
+
+
+ {[...Array(Number(validOwners))].map((x, index) => (
+
+ ))}
+
+
+
+
+ out of
+ {' '}
+ {validOwners}
+ {' '}
+owner(s)
+
+
+
+
+ {qrModalOpen && }
+
+ )
+}
+
+const SafeOwnersForm = withStyles(styles)(SafeOwners)
+
+const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React.Node, { values, errors, form }: Object) => (
+
+
+
+
+
+)
+
+export default SafeOwnersPage
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/style.js b/src/routes/open/components/SafeOwnersConfirmationsForm/style.js
new file mode 100644
index 00000000..600a4b72
--- /dev/null
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/style.js
@@ -0,0 +1,44 @@
+// @flow
+import { md, lg, sm } from '~/theme/variables'
+
+export const styles = () => ({
+ root: {
+ display: 'flex',
+ },
+ title: {
+ padding: `${md} ${lg}`,
+ },
+ owner: {
+ padding: `0 ${lg}`,
+ marginTop: '12px',
+ '&:first-child': {
+ marginTop: 0,
+ },
+ },
+ header: {
+ padding: `${sm} ${lg}`,
+ },
+ name: {
+ marginRight: `${sm}`,
+ },
+ trash: {
+ top: '5px',
+ },
+ add: {
+ justifyContent: 'center',
+ },
+ check: {
+ color: '#03AE60',
+ height: '20px',
+ },
+ remove: {
+ height: '56px',
+ maxWidth: '50px',
+ '&:hover': {
+ cursor: 'pointer',
+ },
+ },
+ owners: {
+ paddingLeft: md,
+ },
+})
diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js b/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js
new file mode 100644
index 00000000..97f877d7
--- /dev/null
+++ b/src/routes/open/components/SafeOwnersConfirmationsForm/validators.js
@@ -0,0 +1,17 @@
+// @flow
+import {
+ required,
+ composeValidators,
+ uniqueAddress,
+ mustBeEthereumAddress,
+} from '~/components/forms/validator'
+
+export const getAddressValidators = (addresses: string[], position: number) => {
+ // thanks Rich Harris
+ // https://twitter.com/Rich_Harris/status/1125850391155965952
+ const copy = addresses.slice()
+ copy[position] = copy[copy.length - 1]
+ copy.pop()
+
+ return composeValidators(required, mustBeEthereumAddress, uniqueAddress(copy))
+}
diff --git a/src/routes/open/components/SafeOwnersForm/index.jsx b/src/routes/open/components/SafeOwnersForm/index.jsx
deleted file mode 100644
index cec64ddc..00000000
--- a/src/routes/open/components/SafeOwnersForm/index.jsx
+++ /dev/null
@@ -1,212 +0,0 @@
-// @flow
-import * as React from 'react'
-import { withStyles } from '@material-ui/core/styles'
-import InputAdornment from '@material-ui/core/InputAdornment'
-import CheckCircle from '@material-ui/icons/CheckCircle'
-import Field from '~/components/forms/Field'
-import TextField from '~/components/forms/TextField'
-import {
- required,
- composeValidators,
- uniqueAddress,
- mustBeEthereumAddress,
- noErrorsOn,
-} from '~/components/forms/validator'
-import Block from '~/components/layout/Block'
-import Button from '~/components/layout/Button'
-import Row from '~/components/layout/Row'
-import Img from '~/components/layout/Img'
-import Col from '~/components/layout/Col'
-import { getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
-import Paragraph from '~/components/layout/Paragraph'
-import OpenPaper from '~/components/Stepper/OpenPaper'
-import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
-import Hairline from '~/components/layout/Hairline'
-import { md, lg, sm } from '~/theme/variables'
-import trash from '~/assets/icons/trash.svg'
-
-type Props = {
- classes: Object,
- otherAccounts: string[],
- errors: Object,
- values: Object,
- updateInitialProps: (initialValues: Object) => void,
-}
-
-type State = {
- numOwners: number,
-}
-
-const styles = () => ({
- root: {
- display: 'flex',
- },
- title: {
- padding: `${md} ${lg}`,
- },
- owner: {
- padding: `0 ${lg}`,
- },
- header: {
- padding: `${sm} ${lg}`,
- },
- name: {
- marginRight: `${sm}`,
- },
- trash: {
- top: '5px',
- },
- add: {
- justifyContent: 'center',
- },
- check: {
- color: '#03AE60',
- height: '20px',
- },
- remove: {
- height: '56px',
- marginTop: '12px',
- maxWidth: '50px',
- '&:hover': {
- cursor: 'pointer',
- },
- },
-})
-
-const getAddressValidators = (addresses: string[], position: number) => {
- // thanks Rich Harris
- // https://twitter.com/Rich_Harris/status/1125850391155965952
- const copy = addresses.slice()
- copy[position] = copy[copy.length - 1]
- copy.pop()
-
- return composeValidators(required, mustBeEthereumAddress, uniqueAddress(copy))
-}
-
-export const ADD_OWNER_BUTTON = '+ ADD ANOTHER OWNER'
-
-export const calculateValuesAfterRemoving = (index: number, notRemovedOwners: number, values: Object) => {
- const initialValues = { ...values }
- const numOwnersAfterRemoving = notRemovedOwners - 1
- // muevo indices
- for (let i = index; i < numOwnersAfterRemoving; i += 1) {
- initialValues[getOwnerNameBy(i)] = values[getOwnerNameBy(i + 1)]
- initialValues[getOwnerAddressBy(i)] = values[getOwnerAddressBy(i + 1)]
- }
-
- delete initialValues[getOwnerNameBy(numOwnersAfterRemoving)]
- delete initialValues[getOwnerAddressBy(numOwnersAfterRemoving)]
-
- return initialValues
-}
-
-class SafeOwners extends React.PureComponent {
- state = {
- numOwners: 1,
- }
-
- onRemoveRow = (index: number) => () => {
- const { values, updateInitialProps } = this.props
- const { numOwners } = this.state
- const initialValues = calculateValuesAfterRemoving(index, numOwners, values)
- updateInitialProps(initialValues)
-
- this.setState(state => ({
- numOwners: state.numOwners - 1,
- }))
- }
-
- onAddOwner = () => {
- this.setState(state => ({
- numOwners: state.numOwners + 1,
- }))
- }
-
- render() {
- const { classes, errors, otherAccounts } = this.props
- const { numOwners } = this.state
-
- return (
-
-
-
- Specify the owners of the Safe.
-
-
-
-
- NAME
- ADDRESS
-
-
-
- {[...Array(Number(numOwners))].map((x, index) => {
- const addressName = getOwnerAddressBy(index)
-
- return (
-
-
-
-
-
-
-
-
- ),
- }
- }
- type="text"
- validate={getAddressValidators(otherAccounts, index)}
- placeholder="Owner Address*"
- text="Owner Address"
- />
-
-
- {index > 0 && }
-
-
- )
- })}
-
-
-
-
-
- )
- }
-}
-
-const SafeOwnersForm = withStyles(styles)(SafeOwners)
-
-const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React.Node, { values, errors }: Object) => (
-
-
-
-
-
-)
-
-export default SafeOwnersPage
diff --git a/src/routes/open/components/SafeThresholdForm/index.jsx b/src/routes/open/components/SafeThresholdForm/index.jsx
deleted file mode 100644
index 9571525f..00000000
--- a/src/routes/open/components/SafeThresholdForm/index.jsx
+++ /dev/null
@@ -1,91 +0,0 @@
-// @flow
-import * as React from 'react'
-import { withStyles } from '@material-ui/core/styles'
-import MenuItem from '@material-ui/core/MenuItem'
-import Field from '~/components/forms/Field'
-import SelectField from '~/components/forms/SelectField'
-import {
- composeValidators, minValue, mustBeInteger, required,
-} from '~/components/forms/validator'
-import Block from '~/components/layout/Block'
-import Row from '~/components/layout/Row'
-import Col from '~/components/layout/Col'
-import Paragraph from '~/components/layout/Paragraph'
-import OpenPaper from '~/components/Stepper/OpenPaper'
-import { FIELD_CONFIRMATIONS, getNumOwnersFrom } from '~/routes/open/components/fields'
-import { md } from '~/theme/variables'
-
-type Props = {
- classes: Object,
- values: Object,
-}
-
-const styles = () => ({
- owners: {
- paddingLeft: md,
- },
-})
-
-export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
-
-export const safeFieldsValidation = (values: Object) => {
- const errors = {}
-
- const numOwners = getNumOwnersFrom(values)
- if (numOwners < Number.parseInt(values[FIELD_CONFIRMATIONS], 10)) {
- errors[FIELD_CONFIRMATIONS] = CONFIRMATIONS_ERROR
- }
-
- return errors
-}
-
-const SafeThreshold = ({ classes, values }: Props) => {
- const numOwners = getNumOwnersFrom(values)
-
- return (
-
-
-
- Any transaction requires the confirmation of:
-
-
-
-
-
- {[...Array(Number(numOwners))].map((x, index) => (
-
- ))}
-
-
-
-
- out of
- {' '}
- {numOwners}
- {' '}
- owner(s)
-
-
-
-
- )
-}
-
-const SafeThresholdForm = withStyles(styles)(SafeThreshold)
-
-const SafeOwnersPage = () => (controls: React.Node, { values }: Object) => (
-
-
-
-
-
-)
-
-export default SafeOwnersPage
diff --git a/src/routes/open/components/fields.js b/src/routes/open/components/fields.js
index 897eb4e4..fa280c90 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+Name$/.test(key))
+ .filter(key => /^owner\d+Address$/.test(key) && !!values[key])
return accounts.length
}
diff --git a/src/routes/safe/components/Balances/Receive/index.jsx b/src/routes/safe/components/Balances/Receive/index.jsx
index 841f6f2a..50c3300a 100644
--- a/src/routes/safe/components/Balances/Receive/index.jsx
+++ b/src/routes/safe/components/Balances/Receive/index.jsx
@@ -4,8 +4,8 @@ import { withStyles } from '@material-ui/core/styles'
import Close from '@material-ui/icons/Close'
import IconButton from '@material-ui/core/IconButton'
import OpenInNew from '@material-ui/icons/OpenInNew'
-import Link from '~/components/layout/Link'
import QRCode from 'qrcode.react'
+import Link from '~/components/layout/Link'
import Paragraph from '~/components/layout/Paragraph'
import Identicon from '~/components/Identicon'
import Button from '~/components/layout/Button'
diff --git a/src/routes/safe/components/SendToken/ReviewTx/index.jsx b/src/routes/safe/components/SendToken/ReviewTx/index.jsx
deleted file mode 100644
index e2a41932..00000000
--- a/src/routes/safe/components/SendToken/ReviewTx/index.jsx
+++ /dev/null
@@ -1,39 +0,0 @@
-// @flow
-import * as React from 'react'
-import CircularProgress from '@material-ui/core/CircularProgress'
-import Block from '~/components/layout/Block'
-import Bold from '~/components/layout/Bold'
-import OpenPaper from '~/components/Stepper/OpenPaper'
-import Heading from '~/components/layout/Heading'
-import Paragraph from '~/components/layout/Paragraph'
-import { TKN_DESTINATION_PARAM, TKN_VALUE_PARAM } from '~/routes/safe/components/SendToken/SendTokenForm/index'
-
-type FormProps = {
- values: Object,
- submitting: boolean,
-}
-
-type Props = {
- symbol: string,
-}
-
-const spinnerStyle = {
- minHeight: '50px',
-}
-
-const ReviewTx = ({ symbol }: Props) => (controls: React.Node, { values, submitting }: FormProps) => (
-
- Review the move token funds
-
- Destination:
- {' '}
- {values[TKN_DESTINATION_PARAM]}
-
-
- {`Amount to transfer: ${values[TKN_VALUE_PARAM]} ${symbol}`}
-
- {submitting && }
-
-)
-
-export default ReviewTx
diff --git a/src/routes/safe/components/SendToken/SendTokenForm/index.jsx b/src/routes/safe/components/SendToken/SendTokenForm/index.jsx
deleted file mode 100644
index 1095a7fe..00000000
--- a/src/routes/safe/components/SendToken/SendTokenForm/index.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-// @flow
-import * as React from 'react'
-import Field from '~/components/forms/Field'
-import TextField from '~/components/forms/TextField'
-import {
- composeValidators, inLimit, mustBeFloat, required, greaterThan, mustBeEthereumAddress,
-} from '~/components/forms/validator'
-import Block from '~/components/layout/Block'
-import OpenPaper from '~/components/Stepper/OpenPaper'
-import Heading from '~/components/layout/Heading'
-
-export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
-
-export const TKN_DESTINATION_PARAM = 'tknDestination'
-export const TKN_VALUE_PARAM = 'tknValue'
-
-type Props = {
- funds: string,
- symbol: string,
-}
-
-const SendTokenForm = ({ funds, symbol }: Props) => (controls: React.Node) => (
-
-
- Send tokens Transaction
-
-
- {`Available tokens: ${funds} ${symbol}`}
-
-
-
-
-
-
-
-
-)
-
-export default SendTokenForm
diff --git a/src/routes/safe/components/SendToken/actions.js b/src/routes/safe/components/SendToken/actions.js
deleted file mode 100644
index 681ad469..00000000
--- a/src/routes/safe/components/SendToken/actions.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// @flow
-import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
-
-export type Actions = {
- fetchTransactions: typeof fetchTransactions,
-}
-
-export default {
- fetchTransactions,
-}
diff --git a/src/routes/safe/components/SendToken/index.jsx b/src/routes/safe/components/SendToken/index.jsx
deleted file mode 100644
index 84899436..00000000
--- a/src/routes/safe/components/SendToken/index.jsx
+++ /dev/null
@@ -1,119 +0,0 @@
-// @flow
-import * as React from 'react'
-import { BigNumber } from 'bignumber.js'
-import { connect } from 'react-redux'
-import Stepper from '~/components/Stepper'
-import { sleep } from '~/utils/timer'
-import { type Safe } from '~/routes/safe/store/models/safe'
-import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
-import { type Token } from '~/logic/tokens/store/model/token'
-import { isEther } from '~/logic/tokens/utils/tokenHelpers'
-import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
-import { toNative } from '~/logic/wallets/tokens'
-import { createTransaction } from '~/logic/safe/safeFrontendOperations'
-import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
-import actions, { type Actions } from './actions'
-import selector, { type SelectorProps } from './selector'
-import SendTokenForm, { TKN_DESTINATION_PARAM, TKN_VALUE_PARAM } from './SendTokenForm'
-import ReviewTx from './ReviewTx'
-
-const getSteps = () => ['Fill Move Token form', 'Review Move Token form']
-
-type Props = SelectorProps &
- Actions & {
- safe: Safe,
- token: Token,
- onReset: () => void,
- }
-
-type State = {
- done: boolean,
-}
-
-export const SEE_TXS_BUTTON_TEXT = 'VISIT TXS'
-
-const getTransferData = async (tokenAddress: string, to: string, amount: BigNumber) => {
- const StandardToken = await getStandardTokenContract()
- const myToken = await StandardToken.at(tokenAddress)
-
- return myToken.contract.transfer(to, amount).encodeABI()
-}
-
-const processTokenTransfer = async (safe: Safe, token: Token, to: string, amount: string, userAddress: string) => {
- const safeAddress = safe.get('address')
- const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
- const nonce = await gnosisSafe.nonce()
- const symbol = token.get('symbol')
- const name = `Send ${amount} ${symbol} to ${to}`
- const value = isEther(symbol) ? amount : '0'
- const tokenAddress = token.get('address')
- const destination = isEther(symbol) ? to : tokenAddress
- const data = isEther(symbol)
- ? EMPTY_DATA
- : await getTransferData(tokenAddress, to, toNative(amount, token.get('decimals')))
-
- return createTransaction(safe, name, destination, value, nonce, userAddress, data)
-}
-
-class SendToken extends React.Component {
- state = {
- done: false,
- }
-
- onTransaction = async (values: Object) => {
- try {
- const {
- safe, token, userAddress, fetchTransactions,
- } = this.props
-
- const amount = values[TKN_VALUE_PARAM]
- const destination = values[TKN_DESTINATION_PARAM]
-
- await processTokenTransfer(safe, token, destination, amount, userAddress)
- await sleep(1500)
- fetchTransactions(safe.get('address'))
- this.setState({ done: true })
- } catch (error) {
- this.setState({ done: false })
- // eslint-disable-next-line
- console.log('Error while moving ERC20 token funds ' + error)
- }
- }
-
- onReset = () => {
- const { onReset } = this.props
-
- this.setState({ done: false })
- onReset() // This is for show the TX list component
- }
-
- render() {
- const { done } = this.state
- const { token } = this.props
- const steps = getSteps()
- const finishedButton =
- const symbol = token.get('symbol')
-
- return (
-
-
-
- {SendTokenForm}
-
- {ReviewTx}
-
-
- )
- }
-}
-
-export default connect(
- selector,
- actions,
-)(SendToken)
diff --git a/src/routes/safe/components/SendToken/selector.js b/src/routes/safe/components/SendToken/selector.js
deleted file mode 100644
index 8701f74b..00000000
--- a/src/routes/safe/components/SendToken/selector.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// @flow
-import { createStructuredSelector } from 'reselect'
-import { userAccountSelector } from '~/logic/wallets/store/selectors'
-
-export type SelectorProps = {
- userAddress: typeof userAccountSelector,
-}
-
-export default createStructuredSelector