refactor createTRansaction method to accept safe settings txs

This commit is contained in:
mmv 2019-06-18 15:55:53 +04:00
parent 4b31e6130e
commit 8ec1d6f528
5 changed files with 108 additions and 104 deletions

View File

@ -12,7 +12,7 @@ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export const executeTransaction = async (
safeInstance: any,
to: string,
valueInWei: number,
valueInWei: number | string,
data: string,
operation: number | string,
nonce: string | number,

View File

@ -17,8 +17,12 @@ import { copyToClipboard } from '~/utils/clipboard'
import Hairline from '~/components/layout/Hairline'
import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo'
import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import ArrowDown from '../assets/arrow-down.svg'
import { secondary } from '~/theme/variables'
import { isEther } from '~/logic/tokens/utils/tokenHelpers'
import { styles } from './style'
type Props = {
@ -50,87 +54,109 @@ const ReviewTx = ({
createTransaction,
}: Props) => (
<SharedSnackbarConsumer>
{({ openSnackbar }) => (
<React.Fragment>
<Row align="center" grow className={classes.heading}>
<Paragraph weight="bolder" className={classes.headingText} noMargin>
Send Funds
</Paragraph>
<Paragraph className={classes.annotation}>2 of 2</Paragraph>
<IconButton onClick={onClose} disableRipple>
<Close className={classes.closeIcon} />
</IconButton>
</Row>
<Hairline />
<Block className={classes.container}>
<SafeInfo
safeAddress={safeAddress}
etherScanLink={etherScanLink}
safeName={safeName}
ethBalance={ethBalance}
/>
<Row margin="md">
<Col xs={1}>
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
</Col>
<Col xs={11} center="xs" layout="column">
<Hairline />
</Col>
</Row>
<Row margin="xs">
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
Recipient
{({ openSnackbar }) => {
const submitTx = async () => {
const web3 = getWeb3()
const isSendingETH = isEther(tx.token.symbol)
const txRecipient = isSendingETH ? tx.recipientAddress : tx.token.address
let txData = EMPTY_DATA
let txAmount = web3.utils.toWei(tx.amount, 'ether')
if (!isSendingETH) {
const StandardToken = await getStandardTokenContract()
const tokenInstance = await StandardToken.at(tx.token.address)
txData = tokenInstance.contract.methods.transfer(tx.recipientAddress, txAmount).encodeABI()
// txAmount should be 0 if we send tokens
// the real value is encoded in txData and will be used by the contract
// if txAmount > 0 it would send ETH from the safe
txAmount = 0
}
createTransaction(safeAddress, txRecipient, txAmount, txData, openSnackbar)
onClose()
}
return (
<React.Fragment>
<Row align="center" grow className={classes.heading}>
<Paragraph weight="bolder" className={classes.headingText} noMargin>
Send Funds
</Paragraph>
<Paragraph className={classes.annotation}>2 of 2</Paragraph>
<IconButton onClick={onClose} disableRipple>
<Close className={classes.closeIcon} />
</IconButton>
</Row>
<Row margin="md" align="center">
<Col xs={1}>
<Identicon address={tx.recipientAddress} diameter={32} />
</Col>
<Col xs={11} layout="column">
<Paragraph weight="bolder" onClick={copyToClipboard} noMargin>
{tx.recipientAddress}
<Link to={etherScanLink} target="_blank">
<OpenInNew style={openIconStyle} />
</Link>
<Hairline />
<Block className={classes.container}>
<SafeInfo
safeAddress={safeAddress}
etherScanLink={etherScanLink}
safeName={safeName}
ethBalance={ethBalance}
/>
<Row margin="md">
<Col xs={1}>
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
</Col>
<Col xs={11} center="xs" layout="column">
<Hairline />
</Col>
</Row>
<Row margin="xs">
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
Recipient
</Paragraph>
</Col>
</Row>
<Row margin="md" align="center">
<Col xs={1}>
<Identicon address={tx.recipientAddress} diameter={32} />
</Col>
<Col xs={11} layout="column">
<Paragraph weight="bolder" onClick={copyToClipboard} noMargin>
{tx.recipientAddress}
<Link to={etherScanLink} target="_blank">
<OpenInNew style={openIconStyle} />
</Link>
</Paragraph>
</Col>
</Row>
<Row margin="xs">
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
Amount
</Paragraph>
</Row>
<Row margin="md" align="center">
<Img src={tx.token.logoUri} height={28} alt={tx.token.name} onError={setImageToPlaceholder} />
<Paragraph size="md" noMargin className={classes.amount}>
{tx.amount}
{' '}
{tx.token.symbol}
</Paragraph>
</Row>
</Block>
<Hairline style={{ position: 'absolute', bottom: 85 }} />
<Row align="center" className={classes.buttonRow}>
<Button className={classes.button} minWidth={140} onClick={onClickBack}>
Back
</Button>
<Button
type="submit"
className={classes.button}
onClick={submitTx}
variant="contained"
minWidth={140}
color="primary"
data-testid="submit-tx-btn"
>
SUBMIT
</Button>
</Row>
<Row margin="xs">
<Paragraph size="md" color="disabled" style={{ letterSpacing: '-0.5px' }} noMargin>
Amount
</Paragraph>
</Row>
<Row margin="md" align="center">
<Img src={tx.token.logoUri} height={28} alt={tx.token.name} onError={setImageToPlaceholder} />
<Paragraph size="md" noMargin className={classes.amount}>
{tx.amount}
{' '}
{tx.token.symbol}
</Paragraph>
</Row>
</Block>
<Hairline style={{ position: 'absolute', bottom: 85 }} />
<Row align="center" className={classes.buttonRow}>
<Button className={classes.button} minWidth={140} onClick={onClickBack}>
Back
</Button>
<Button
type="submit"
className={classes.button}
onClick={() => {
createTransaction(safeAddress, tx.recipientAddress, tx.amount, tx.token, openSnackbar)
onClose()
}}
variant="contained"
minWidth={140}
color="primary"
data-testid="submit-tx-btn"
>
SUBMIT
</Button>
</Row>
</React.Fragment>
)}
</React.Fragment>
)
}}
</SharedSnackbarConsumer>
)

View File

@ -18,7 +18,6 @@ import {
sm, xs, secondary, smallFontSize,
} from '~/theme/variables'
import { copyToClipboard } from '~/utils/clipboard'
import type { Safe } from '~/routes/safe/store/models/safe'
import Balances from './Balances'
import Settings from './Settings'

View File

@ -11,7 +11,7 @@ export type Props = Actions &
granted: boolean,
}
const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 15000
const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 5000
class SafeView extends React.Component<Props> {
componentDidMount() {

View File

@ -1,15 +1,11 @@
// @flow
import type { Dispatch as ReduxDispatch, GetState } from 'redux'
import { createAction } from 'redux-actions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { type Token } from '~/logic/tokens/store/model/token'
import { userAccountSelector } from '~/logic/wallets/store/selectors'
import { type GlobalState } from '~/store'
import { isEther } from '~/logic/tokens/utils/tokenHelpers'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
import { executeTransaction, CALL } from '~/logic/safe/transactions'
import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
export const ADD_TRANSACTIONS = 'ADD_TRANSACTIONS'
export const addTransactions = createAction<string, *>(ADD_TRANSACTIONS)
@ -17,40 +13,23 @@ export const addTransactions = createAction<string, *>(ADD_TRANSACTIONS)
const createTransaction = (
safeAddress: string,
to: string,
valueInEth: string,
token: Token,
openSnackbar: Function,
valueInWei: string,
txData: string = EMPTY_DATA,
openSnackbar: Function,
) => async (dispatch: ReduxDispatch<GlobalState>, getState: GetState<GlobalState>) => {
const isSendingETH = isEther(token.symbol)
const state: GlobalState = getState()
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const web3 = getWeb3()
const from = userAccountSelector(state)
const threshold = await safeInstance.getThreshold()
const nonce = await safeInstance.nonce()
const txRecipient = isSendingETH ? to : token.address
const valueInWei = web3.utils.toWei(valueInEth, 'ether')
let txAmount = valueInWei
const isExecution = threshold.toNumber() === 1
let txData = EMPTY_DATA
if (!isSendingETH) {
const StandardToken = await getStandardTokenContract()
const sendToken = await StandardToken.at(token.address)
txData = sendToken.contract.methods.transfer(to, valueInWei).encodeABI()
// txAmount should be 0 if we send tokens
// the real value is encoded in txData and will be used by the contract
// if txAmount > 0 it would send ETH from the safe
txAmount = 0
}
let txHash
if (isExecution) {
openSnackbar('Transaction has been submitted', 'success')
txHash = await executeTransaction(safeInstance, txRecipient, txAmount, txData, CALL, nonce, from)
txHash = await executeTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from)
openSnackbar('Transaction has been confirmed', 'success')
} else {
// txHash = await approveTransaction(safeAddress, to, valueInWei, txData, CALL, nonce)