WA-438 Add withdrawn transactions to list

This commit is contained in:
apanizo 2018-06-22 13:13:52 +02:00
parent 63bba3ccd5
commit d58bcf9bb8
9 changed files with 74 additions and 34 deletions

View File

@ -55,7 +55,7 @@ class GnoSafe extends React.PureComponent<SafeProps, State> {
onWithdraw = () => { onWithdraw = () => {
const { safe } = this.props const { safe } = this.props
this.setState({ component: <Withdraw safeAddress={safe.get('address')} dailyLimit={safe.get('dailyLimit')} /> }) this.setState({ component: <Withdraw safe={safe} dailyLimit={safe.get('dailyLimit')} /> })
} }
onAddTx = () => { onAddTx = () => {

View File

@ -0,0 +1,12 @@
// @flow
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
type FetchTransactions = typeof fetchTransactions
export type Actions = {
fetchTransactions: FetchTransactions,
}
export default {
fetchTransactions,
}

View File

@ -3,17 +3,19 @@ import * as React from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import Stepper from '~/components/Stepper' import Stepper from '~/components/Stepper'
import { type DailyLimit } from '~/routes/safe/store/model/dailyLimit' import { type DailyLimit } from '~/routes/safe/store/model/dailyLimit'
import { type Safe } from '~/routes/safe/store/model/safe'
import selector, { type SelectorProps } from './selector' import selector, { type SelectorProps } from './selector'
import withdraw from './withdraw' import withdraw from './withdraw'
import WithdrawForm from './WithdrawForm' import WithdrawForm from './WithdrawForm'
import Review from './Review' import Review from './Review'
import actions, { type Actions } from './actions'
const getSteps = () => [ const getSteps = () => [
'Fill Withdraw Form', 'Review Withdraw', 'Fill Withdraw Form', 'Review Withdraw',
] ]
type Props = SelectorProps & { type Props = SelectorProps & Actions & {
safeAddress: string, safe: Safe,
dailyLimit: DailyLimit, dailyLimit: DailyLimit,
} }
@ -30,8 +32,10 @@ class Withdraw extends React.Component<Props, State> {
onWithdraw = async (values: Object) => { onWithdraw = async (values: Object) => {
try { try {
const { safeAddress, userAddress } = this.props const { safe, userAddress, fetchTransactions } = this.props
await withdraw(values, safeAddress, userAddress) await withdraw(values, safe, userAddress)
fetchTransactions()
this.setState({ done: true }) this.setState({ done: true })
} catch (error) { } catch (error) {
this.setState({ done: false }) this.setState({ done: false })
@ -71,5 +75,5 @@ class Withdraw extends React.Component<Props, State> {
} }
} }
export default connect(selector)(Withdraw) export default connect(selector, actions)(Withdraw)

View File

@ -3,6 +3,8 @@ import { getWeb3 } from '~/wallets/getWeb3'
import { getGnosisSafeContract, getCreateDailyLimitExtensionContract } from '~/wallets/safeContracts' import { getGnosisSafeContract, getCreateDailyLimitExtensionContract } from '~/wallets/safeContracts'
import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit' import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit'
import { checkReceiptStatus, calculateGasOf, calculateGasPrice } from '~/wallets/ethTransactions' import { checkReceiptStatus, calculateGasOf, calculateGasPrice } from '~/wallets/ethTransactions'
import { type Safe } from '~/routes/safe/store/model/safe'
import { buildExecutedConfirmationFrom, storeTransaction } from '~/routes/safe/component/AddTransaction/createTransactions'
export const LIMIT_POSITION = 0 export const LIMIT_POSITION = 0
export const SPENT_TODAY_POS = 1 export const SPENT_TODAY_POS = 1
@ -49,12 +51,14 @@ export const getEditDailyLimitData = async (safeAddress: string, token: string,
return dailyLimitModule.contract.changeDailyLimit.getData(token, dailyLimitInWei) return dailyLimitModule.contract.changeDailyLimit.getData(token, dailyLimitInWei)
} }
const withdraw = async (values: Object, safeAddress: string, userAccount: string): Promise<void> => { const withdraw = async (values: Object, safe: Safe, userAccount: string): Promise<void> => {
const web3 = getWeb3() const web3 = getWeb3()
const safeAddress = safe.get('address')
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress) const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
const destination = values[DESTINATION_PARAM] const destination = values[DESTINATION_PARAM]
const value = web3.toWei(values[VALUE_PARAM], 'ether') const valueInEth = values[VALUE_PARAM]
const value = web3.toWei(valueInEth, 'ether')
const dailyLimitData = dailyLimitModule.contract.executeDailyLimit.getData(0, destination, value) const dailyLimitData = dailyLimitModule.contract.executeDailyLimit.getData(0, destination, value)
const gas = await calculateGasOf(dailyLimitData, userAccount, dailyLimitModule.address) const gas = await calculateGasOf(dailyLimitData, userAccount, dailyLimitModule.address)
@ -62,6 +66,11 @@ const withdraw = async (values: Object, safeAddress: string, userAccount: string
const txHash = await dailyLimitModule.executeDailyLimit(0, destination, value, { from: userAccount, gas, gasPrice }) const txHash = await dailyLimitModule.executeDailyLimit(0, destination, value, { from: userAccount, gas, gasPrice })
checkReceiptStatus(txHash.tx) checkReceiptStatus(txHash.tx)
const nonce = Date.now()
const executedConfirmations: List<Confirmation> = buildExecutedConfirmationFrom(safe.get('owners'), userAccount)
return storeTransaction(`Withdraw movement of ${valueInEth}`, nonce, destination, valueInEth, userAccount, executedConfirmations, txHash.tx, safeAddress, safe.get('threshold'), '0x')
} }
export default withdraw export default withdraw

View File

@ -2,6 +2,8 @@
import { aNewStore } from '~/store' import { aNewStore } from '~/store'
import { addEtherTo } from '~/test/utils/etherMovements' import { addEtherTo } from '~/test/utils/etherMovements'
import { aDeployedSafe, executeWithdrawOn } from '~/routes/safe/store/test/builder/deployedSafe.builder' import { aDeployedSafe, executeWithdrawOn } from '~/routes/safe/store/test/builder/deployedSafe.builder'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { safeSelector } from '~/routes/safe/store/selectors/index'
describe('Safe Blockchain Test', () => { describe('Safe Blockchain Test', () => {
let store let store
@ -17,8 +19,10 @@ describe('Safe Blockchain Test', () => {
const value = 0.15 const value = 0.15
// WHEN // WHEN
await executeWithdrawOn(safeAddress, value) const match: Match = buildMathPropsFrom(safeAddress)
await executeWithdrawOn(safeAddress, value) const safe = safeSelector(store.getState(), { match })
await executeWithdrawOn(safe, value)
await executeWithdrawOn(safe, value)
// THEN // THEN
expect(executeWithdrawOn(safeAddress, value)).rejects.toThrow('VM Exception while processing transaction: revert') expect(executeWithdrawOn(safeAddress, value)).rejects.toThrow('VM Exception while processing transaction: revert')

View File

@ -13,6 +13,7 @@ import addProvider from '~/wallets/store/actions/addProvider'
import { makeProvider } from '~/wallets/store/model/provider' import { makeProvider } from '~/wallets/store/model/provider'
import withdraw, { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/withdraw' import withdraw, { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/withdraw'
import { promisify } from '~/utils/promisify' import { promisify } from '~/utils/promisify'
import { type Safe } from '~/routes/safe/store/model/safe'
export const renderSafe = async (localStore: Store<GlobalState>) => { export const renderSafe = async (localStore: Store<GlobalState>) => {
const provider = await getProviderInfo() const provider = await getProviderInfo()
@ -94,7 +95,7 @@ export const aDeployedSafe = async (
return deployedSafe.logs[1].args.proxy return deployedSafe.logs[1].args.proxy
} }
export const executeWithdrawOn = async (safeAddress: string, value: number) => { export const executeWithdrawOn = async (safe: Safe, value: number) => {
const providerInfo = await getProviderInfo() const providerInfo = await getProviderInfo()
const userAddress = providerInfo.account const userAddress = providerInfo.account
@ -103,5 +104,5 @@ export const executeWithdrawOn = async (safeAddress: string, value: number) => {
[VALUE_PARAM]: `${value}`, [VALUE_PARAM]: `${value}`,
} }
return withdraw(values, safeAddress, userAddress) return withdraw(values, safe, userAddress)
} }

View File

@ -18,6 +18,8 @@ import { getDailyLimitFrom } from '~/routes/safe/component/Withdraw/withdraw'
import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit' import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit'
import { ADD_MULTISIG_BUTTON_TEXT } from '~/routes/safe/component/Safe/MultisigTx' import { ADD_MULTISIG_BUTTON_TEXT } from '~/routes/safe/component/Safe/MultisigTx'
import { WITHDRAW_INDEX, MOVE_FUNDS_INDEX } from '~/test/builder/safe.dom.utils' import { WITHDRAW_INDEX, MOVE_FUNDS_INDEX } from '~/test/builder/safe.dom.utils'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { safeSelector } from '~/routes/safe/store/selectors/index'
describe('React DOM TESTS > Withdraw funds from safe', () => { describe('React DOM TESTS > Withdraw funds from safe', () => {
let SafeDom let SafeDom
@ -80,10 +82,10 @@ describe('React DOM TESTS > Withdraw funds from safe', () => {
// add funds to safe // add funds to safe
await addEtherTo(address, '0.1') await addEtherTo(address, '0.1')
// GIVEN in beforeEach const match: Match = buildMathPropsFrom(address)
// WHEN const safe = safeSelector(store.getState(), { match })
await executeWithdrawOn(address, 0.01) await executeWithdrawOn(safe, 0.01)
await executeWithdrawOn(address, 0.01) await executeWithdrawOn(safe, 0.01)
const ethAddress = 0 const ethAddress = 0
const dailyLimit: DailyLimitProps = await getDailyLimitFrom(address, ethAddress) const dailyLimit: DailyLimitProps = await getDailyLimitFrom(address, ethAddress)

View File

@ -33,9 +33,9 @@ describe('DOM > Feature > SAFE MULTISIG TX 1 Owner 1 Threshold', () => {
const transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) const transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
checkMinedMoveFundsTx(transactions[0], 'Move funds') checkMinedMoveFundsTx(transactions[0], 'Move funds')
await checkMinedWithdrawTx(address, '0.08') // 0.1 - 0.01 tx - 0.01 withdraw await checkMinedWithdrawTx(transactions[1], 'Withdraw movement of 0.01', address, '0.08') // 0.1 - 0.01 tx - 0.01 withdraw
checkMinedAddOwnerTx(transactions[1], 'Add Owner Adol Metamask 2') checkMinedAddOwnerTx(transactions[2], 'Add Owner Adol Metamask 2')
checkMinedThresholdTx(transactions[2], 'Change Safe\'s threshold') checkMinedThresholdTx(transactions[3], 'Change Safe\'s threshold')
}) })
it('mines withdraw process correctly all multisig txs in a 2 owner & 2 threshold safe', async () => { it('mines withdraw process correctly all multisig txs in a 2 owner & 2 threshold safe', async () => {
@ -55,10 +55,10 @@ describe('DOM > Feature > SAFE MULTISIG TX 1 Owner 1 Threshold', () => {
const transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) const transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
const statusses = ['Adol Metamask 2 [Not confirmed]', 'Adolfo 1 Eth Account [Confirmed]'] const statusses = ['Adol Metamask 2 [Not confirmed]', 'Adolfo 1 Eth Account [Confirmed]']
await checkPendingMoveFundsTx(transactions[3], 2, 'Buy batteries', statusses) await checkPendingMoveFundsTx(transactions[4], 2, 'Buy batteries', statusses)
await checkPendingAddOwnerTx(transactions[4], 2, 'Add Owner Adol Metamask 3', statusses) await checkPendingAddOwnerTx(transactions[5], 2, 'Add Owner Adol Metamask 3', statusses)
// checkMinedThresholdTx(transactions[4], 'Add Owner Adol Metamask 3') // checkMinedThresholdTx(transactions[4], 'Add Owner Adol Metamask 3')
await checkMinedWithdrawTx(address, '0.07') await checkMinedWithdrawTx(transactions[6], 'Withdraw movement of 0.01', address, '0.07')
}) })
it('approves and executes pending transactions', async () => { it('approves and executes pending transactions', async () => {
@ -68,17 +68,17 @@ describe('DOM > Feature > SAFE MULTISIG TX 1 Owner 1 Threshold', () => {
} = domSafe } = domSafe
let transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) let transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
expect(transactions.length).toBe(5) expect(transactions.length).toBe(7)
// WHEN... processing pending TXs // WHEN... processing pending TXs
await processTransaction(address, transactions[3].props.transaction, 1, accounts[1])
await processTransaction(address, transactions[4].props.transaction, 1, accounts[1]) await processTransaction(address, transactions[4].props.transaction, 1, accounts[1])
await processTransaction(address, transactions[5].props.transaction, 1, accounts[1])
await refreshTransactions(store) await refreshTransactions(store)
// THEN // THEN
checkMinedMoveFundsTx(transactions[3], 'Buy batteries') checkMinedMoveFundsTx(transactions[4], 'Buy batteries')
await checkBalanceOf(address, '0.06') await checkBalanceOf(address, '0.06')
checkMinedAddOwnerTx(transactions[4], 'Add Owner Adol Metamask 3') checkMinedAddOwnerTx(transactions[5], 'Add Owner Adol Metamask 3')
await checkThresholdOf(address, 3) await checkThresholdOf(address, 3)
// WHEN... reducing threshold // WHEN... reducing threshold
@ -87,22 +87,22 @@ describe('DOM > Feature > SAFE MULTISIG TX 1 Owner 1 Threshold', () => {
// THEN // THEN
await listTxsClickingOn(safeButtons[LIST_TXS_INDEX]) await listTxsClickingOn(safeButtons[LIST_TXS_INDEX])
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
expect(transactions.length).toBe(6) expect(transactions.length).toBe(8)
let statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Not confirmed]', 'Adolfo 1 Eth Account [Confirmed]'] let statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Not confirmed]', 'Adolfo 1 Eth Account [Confirmed]']
await checkPendingRemoveOwnerTx(transactions[5], 3, 'Remove Owner Adol Metamask 3', statusses) await checkPendingRemoveOwnerTx(transactions[7], 3, 'Remove Owner Adol Metamask 3', statusses)
await processTransaction(address, transactions[5].props.transaction, 1, accounts[1]) await processTransaction(address, transactions[7].props.transaction, 1, accounts[1])
await refreshTransactions(store) await refreshTransactions(store)
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Confirmed]', 'Adolfo 1 Eth Account [Confirmed]'] statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Confirmed]', 'Adolfo 1 Eth Account [Confirmed]']
await checkPendingRemoveOwnerTx(transactions[5], 2, 'Remove Owner Adol Metamask 3', statusses) await checkPendingRemoveOwnerTx(transactions[7], 2, 'Remove Owner Adol Metamask 3', statusses)
await checkThresholdOf(address, 3) await checkThresholdOf(address, 3)
await processTransaction(address, transactions[5].props.transaction, 2, accounts[2]) await processTransaction(address, transactions[7].props.transaction, 2, accounts[2])
await refreshTransactions(store) await refreshTransactions(store)
await checkThresholdOf(address, 2) await checkThresholdOf(address, 2)
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
await checkMinedRemoveOwnerTx(transactions[5], 'Remove Owner') await checkMinedRemoveOwnerTx(transactions[7], 'Remove Owner')
// WHEN... changing threshold // WHEN... changing threshold
await sendChangeThresholdForm(SafeDom, safeButtons[EDIT_THRESHOLD_INDEX], '1') await sendChangeThresholdForm(SafeDom, safeButtons[EDIT_THRESHOLD_INDEX], '1')
@ -110,7 +110,7 @@ describe('DOM > Feature > SAFE MULTISIG TX 1 Owner 1 Threshold', () => {
// THEN // THEN
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction) transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
await processTransaction(address, transactions[6].props.transaction, 1, accounts[1]) await processTransaction(address, transactions[8].props.transaction, 1, accounts[1])
await checkThresholdOf(address, 1) await checkThresholdOf(address, 1)
}) })
}) })

View File

@ -2,6 +2,7 @@
import TestUtils from 'react-dom/test-utils' import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer' import { sleep } from '~/utils/timer'
import { checkBalanceOf } from '~/test/utils/etherMovements' import { checkBalanceOf } from '~/test/utils/etherMovements'
import { checkMinedTx } from '~/test/builder/safe.dom.utils'
export const sendWithdrawForm = ( export const sendWithdrawForm = (
SafeDom: React$Component<any, any>, SafeDom: React$Component<any, any>,
@ -31,6 +32,13 @@ export const sendWithdrawForm = (
return sleep(2500) return sleep(2500)
} }
export const checkMinedWithdrawTx = async (address: string, funds: number) => { export const checkMinedWithdrawTx = async (
Transaction: React$Component<any, any>,
name: string,
address: string,
funds: number,
) => {
await checkBalanceOf(address, funds) await checkBalanceOf(address, funds)
checkMinedTx(Transaction, name)
} }