diff --git a/src/components/forms/validator.js b/src/components/forms/validator.js
index f807840c..8637f158 100644
--- a/src/components/forms/validator.js
+++ b/src/components/forms/validator.js
@@ -8,6 +8,14 @@ export const required = (value: Field) => (value ? undefined : 'Required')
export const mustBeNumber = (value: number) =>
(Number.isNaN(Number(value)) ? 'Must be a number' : undefined)
+export const greaterThan = (min: number) => (value: string) => {
+ if (Number.isNaN(Number(value)) || Number.parseFloat(value) > Number(min)) {
+ return undefined
+ }
+
+ return `Should be greater than ${min}`
+}
+
export const minValue = (min: number) => (value: string) => {
if (Number.isNaN(Number(value)) || Number.parseInt(value, 10) >= Number(min)) {
return undefined
diff --git a/src/routes/open/components/Layout.test.js b/src/routes/open/components/Layout.test.js
index 4193d974..db2eaf1f 100644
--- a/src/routes/open/components/Layout.test.js
+++ b/src/routes/open/components/Layout.test.js
@@ -1,7 +1,14 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { store } from '~/store'
-import { FIELD_NAME, FIELD_OWNERS, FIELD_CONFIRMATIONS, getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
+import {
+ FIELD_NAME,
+ FIELD_OWNERS,
+ FIELD_CONFIRMATIONS,
+ FIELD_DAILY_LIMIT,
+ getOwnerNameBy,
+ getOwnerAddressBy,
+} from '~/routes/open/components/fields'
import { DEPLOYED_COMPONENT_ID } from '~/routes/open/components/FormConfirmation'
import { sleep } from '~/utils/timer'
import { getProviderInfo } from '~/wallets/getWeb3'
@@ -26,6 +33,9 @@ describe('React DOM TESTS > Create Safe form', () => {
const fieldConfirmations = inputs[2]
expect(fieldConfirmations.name).toEqual(FIELD_CONFIRMATIONS)
+ const dailyLimitConfirmations = inputs[3]
+ expect(dailyLimitConfirmations.name).toEqual(FIELD_DAILY_LIMIT)
+
TestUtils.Simulate.change(fieldOwners, { target: { value: '1' } })
const inputsExpanded = TestUtils.scryRenderedDOMComponentsWithTag(open, 'input')
@@ -39,6 +49,7 @@ describe('React DOM TESTS > Create Safe form', () => {
TestUtils.Simulate.change(fieldName, { target: { value: 'Adolfo Safe' } })
TestUtils.Simulate.change(fieldConfirmations, { target: { value: '1' } })
TestUtils.Simulate.change(ownerName, { target: { value: 'Adolfo Eth Account' } })
+ TestUtils.Simulate.change(dailyLimitConfirmations, { target: { value: '10' } })
const form = TestUtils.findRenderedDOMComponentWithTag(open, 'form')
// One submit per step when creating a safe
diff --git a/src/routes/open/components/ReviewInformation/index.jsx b/src/routes/open/components/ReviewInformation/index.jsx
index 8b2b286a..2909aa8c 100644
--- a/src/routes/open/components/ReviewInformation/index.jsx
+++ b/src/routes/open/components/ReviewInformation/index.jsx
@@ -7,6 +7,7 @@ import Col from '~/components/layout/Col'
import Heading from '~/components/layout/Heading'
import Row from '~/components/layout/Row'
import Paragraph from '~/components/layout/Paragraph'
+import { FIELD_NAME, FIELD_CONFIRMATIONS, FIELD_DAILY_LIMIT } from '../fields'
type FormProps = {
values: Object,
@@ -20,10 +21,13 @@ const ReviewInformation = () => ({ values }: FormProps) => {
Review the Safe information
- Safe Name: {values.name}
+ Safe Name: {values[FIELD_NAME]}
- Required confirmations: {values.confirmations}
+ Required confirmations: {values[FIELD_CONFIRMATIONS]}
+
+
+ Daily limit: {values[FIELD_DAILY_LIMIT]} ETH
Owners
{ names.map((name, index) => (
diff --git a/src/routes/open/components/SafeForm/Confirmations/index.test.js b/src/routes/open/components/SafeForm/Confirmations/index.test.js
index a86ae028..2c95c3c5 100644
--- a/src/routes/open/components/SafeForm/Confirmations/index.test.js
+++ b/src/routes/open/components/SafeForm/Confirmations/index.test.js
@@ -49,7 +49,7 @@ describe('React DOM TESTS > Create Safe form', () => {
// THEN
const muiFields = TestUtils.scryRenderedComponentsWithType(open, TextField)
- expect(5).toEqual(muiFields.length)
+ expect(6).toEqual(muiFields.length)
const confirmationsField = muiFields[4]
expect(confirmationsField.props.meta.valid).toBe(false)
@@ -64,7 +64,7 @@ describe('React DOM TESTS > Create Safe form', () => {
// THEN
const muiFields = TestUtils.scryRenderedComponentsWithType(open, TextField)
- expect(7).toEqual(muiFields.length)
+ expect(8).toEqual(muiFields.length)
const confirmationsField = muiFields[6]
expect(confirmationsField.props.meta.valid).toBe(false)
diff --git a/src/routes/open/components/SafeForm/DailyLimit/index.jsx b/src/routes/open/components/SafeForm/DailyLimit/index.jsx
new file mode 100644
index 00000000..83c4ff6b
--- /dev/null
+++ b/src/routes/open/components/SafeForm/DailyLimit/index.jsx
@@ -0,0 +1,22 @@
+// @flow
+import * as React from 'react'
+import Field from '~/components/forms/Field'
+import TextField from '~/components/forms/TextField'
+import { composeValidators, mustBeNumber, required, greaterThan } from '~/components/forms/validator'
+import Block from '~/components/layout/Block'
+import { FIELD_DAILY_LIMIT } from '~/routes/open/components/fields'
+
+const DailyLimit = () => (
+
+
+
+)
+
+export default DailyLimit
diff --git a/src/routes/open/components/SafeForm/index.jsx b/src/routes/open/components/SafeForm/index.jsx
index 478e2e83..b79d00a2 100644
--- a/src/routes/open/components/SafeForm/index.jsx
+++ b/src/routes/open/components/SafeForm/index.jsx
@@ -6,6 +6,7 @@ import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import Name from './Name'
import Owners from './Owners'
import Confirmations from './Confirmations'
+import DailyLimit from './DailyLimit'
export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
@@ -25,5 +26,6 @@ export default () => ({ values }: Object) => (
+
)
diff --git a/src/routes/open/components/fields.js b/src/routes/open/components/fields.js
index b7e37ac9..6755b839 100644
--- a/src/routes/open/components/fields.js
+++ b/src/routes/open/components/fields.js
@@ -2,6 +2,7 @@
export const FIELD_NAME: string = 'name'
export const FIELD_CONFIRMATIONS: string = 'confirmations'
export const FIELD_OWNERS: string = 'owners'
+export const FIELD_DAILY_LIMIT: string = 'limit'
export const getOwnerNameBy = (index: number) => `owner${index}Name`
export const getOwnerAddressBy = (index: number) => `owner${index}Address`
diff --git a/src/routes/open/container/Open.jsx b/src/routes/open/container/Open.jsx
index c80aadf4..e3897ef7 100644
--- a/src/routes/open/container/Open.jsx
+++ b/src/routes/open/container/Open.jsx
@@ -3,7 +3,7 @@ import * as React from 'react'
import { connect } from 'react-redux'
import contract from 'truffle-contract'
import Page from '~/components/layout/Page'
-import { getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom } from '~/routes/open/utils/safeDataExtractor'
+import { getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getDailyLimitFrom } from '~/routes/open/utils/safeDataExtractor'
import { getWeb3 } from '~/wallets/getWeb3'
import { promisify } from '~/utils/promisify'
import Safe from '#/GnosisSafe.json'
@@ -26,12 +26,13 @@ const createSafe = async (safeContract, values, userAccount, addSafe) => {
const numConfirmations = getThresholdFrom(values)
const name = getSafeNameFrom(values)
const owners = getNamesFrom(values)
+ const dailyLimit = getDailyLimitFrom(values)
const web3 = getWeb3()
safeContract.setProvider(web3.currentProvider)
const safe = await safeContract.new(accounts, numConfirmations, 0, 0, { from: userAccount, gas: '5000000' })
- addSafe(name, safe.address, numConfirmations, owners, accounts)
+ addSafe(name, safe.address, numConfirmations, dailyLimit, owners, accounts)
return safe
}
diff --git a/src/routes/open/utils/safeDataExtractor.js b/src/routes/open/utils/safeDataExtractor.js
index e0d84130..25a91fc5 100644
--- a/src/routes/open/utils/safeDataExtractor.js
+++ b/src/routes/open/utils/safeDataExtractor.js
@@ -1,4 +1,6 @@
// @flow
+export const getDailyLimitFrom = (values: Object): number => Number(values.limit)
+
export const getAccountsFrom = (values: Object): string[] => {
const accounts = Object.keys(values).sort().filter(key => /^owner\d+Address$/.test(key))
diff --git a/src/routes/safe/component/Safe/DailyLimit.jsx b/src/routes/safe/component/Safe/DailyLimit.jsx
new file mode 100644
index 00000000..20bd47c7
--- /dev/null
+++ b/src/routes/safe/component/Safe/DailyLimit.jsx
@@ -0,0 +1,21 @@
+// @flow
+import * as React from 'react'
+import { ListItem } from 'material-ui/List'
+import Avatar from 'material-ui/Avatar'
+import NotificationsPaused from 'material-ui-icons/NotificationsPaused'
+import ListItemText from '~/components/List/ListItemText'
+
+type Props = {
+ limit: number,
+}
+
+const DailyLimit = ({ limit }: Props) => (
+
+
+
+
+
+
+)
+
+export default DailyLimit
diff --git a/src/routes/safe/component/Safe/Owners.jsx b/src/routes/safe/component/Safe/Owners.jsx
index e552beb1..e4801fb0 100644
--- a/src/routes/safe/component/Safe/Owners.jsx
+++ b/src/routes/safe/component/Safe/Owners.jsx
@@ -39,7 +39,7 @@ const Owners = openHoc(({
{owners.map(owner => (
-
+
diff --git a/src/routes/safe/component/Safe/index.jsx b/src/routes/safe/component/Safe/index.jsx
index 40a1c9c6..442373e5 100644
--- a/src/routes/safe/component/Safe/index.jsx
+++ b/src/routes/safe/component/Safe/index.jsx
@@ -12,6 +12,7 @@ import Address from './Address'
import Balance from './Balance'
import Owners from './Owners'
import Confirmations from './Confirmations'
+import DailyLimit from './DailyLimit'
type SafeProps = {
safe: Safe,
@@ -20,6 +21,7 @@ type SafeProps = {
const listStyle = {
width: '100%',
+ minWidth: '485px',
}
class GnoSafe extends React.PureComponent {
@@ -34,6 +36,7 @@ class GnoSafe extends React.PureComponent {
+
diff --git a/src/routes/safe/store/actions/addSafe.js b/src/routes/safe/store/actions/addSafe.js
index 8a7a924f..e4a1801e 100644
--- a/src/routes/safe/store/actions/addSafe.js
+++ b/src/routes/safe/store/actions/addSafe.js
@@ -15,13 +15,14 @@ export const buildOwnersFrom = (names: string[], addresses: string[]) => {
const addSafe = createAction(
ADD_SAFE,
(
- name: string, address: string, confirmations: number,
+ name: string, address: string,
+ confirmations: number, dailyLimit: number,
ownersName: string[], ownersAddress: string[],
): SafeProps => {
const owners: List = buildOwnersFrom(ownersName, ownersAddress)
return ({
- address, name, confirmations, owners,
+ address, name, confirmations, owners, dailyLimit,
})
},
)
diff --git a/src/routes/safe/store/model/safe.js b/src/routes/safe/store/model/safe.js
index 146085a0..28e25209 100644
--- a/src/routes/safe/store/model/safe.js
+++ b/src/routes/safe/store/model/safe.js
@@ -8,6 +8,7 @@ export type SafeProps = {
address: string,
confirmations: number,
owners: List,
+ dailyLimit: number,
}
export const makeSafe: RecordFactory = Record({
@@ -15,6 +16,7 @@ export const makeSafe: RecordFactory = Record({
address: '',
confirmations: 0,
owners: List([]),
+ dailyLimit: 0,
})
export type Safe = RecordOf
diff --git a/src/routes/safe/store/test/builder/deployedSafe.builder.js b/src/routes/safe/store/test/builder/deployedSafe.builder.js
index 34bb71b0..6c9b9dca 100644
--- a/src/routes/safe/store/test/builder/deployedSafe.builder.js
+++ b/src/routes/safe/store/test/builder/deployedSafe.builder.js
@@ -33,6 +33,7 @@ const deploySafe = async (safe: React$Component<{}>) => {
const fieldName = inputs[0]
const fieldOwners = inputs[1]
const fieldConfirmations = inputs[2]
+ const fieldDailyLimit = inputs[3]
TestUtils.Simulate.change(fieldOwners, { target: { value: '1' } })
const inputsExpanded = TestUtils.scryRenderedDOMComponentsWithTag(safe, 'input')
@@ -41,6 +42,7 @@ const deploySafe = async (safe: React$Component<{}>) => {
TestUtils.Simulate.change(fieldName, { target: { value: 'Adolfo Safe' } })
TestUtils.Simulate.change(fieldConfirmations, { target: { value: '1' } })
TestUtils.Simulate.change(ownerName, { target: { value: 'Adolfo Eth Account' } })
+ TestUtils.Simulate.change(fieldDailyLimit, { target: { value: '10' } })
const form = TestUtils.findRenderedDOMComponentWithTag(safe, 'form')
diff --git a/src/routes/safe/store/test/builder/safe.builder.js b/src/routes/safe/store/test/builder/safe.builder.js
index d7ad86bd..0bde9e05 100644
--- a/src/routes/safe/store/test/builder/safe.builder.js
+++ b/src/routes/safe/store/test/builder/safe.builder.js
@@ -24,6 +24,11 @@ class SafeBuilder {
return this
}
+ withDailyLimit(limit: number) {
+ this.safe = this.safe.set('dailyLimit', limit)
+ return this
+ }
+
withOwner(names: string[], adresses: string[]) {
const owners = buildOwnersFrom(names, adresses)
this.safe = this.safe.set('owners', owners)
@@ -42,6 +47,7 @@ export class SafeFactory {
.withAddress('0x03db1a8b26d08df23337e9276a36b474510f0025')
.withName('Adol ICO Safe')
.withConfirmations(1)
+ .withDailyLimit(10)
.withOwner(['Adol Metamask'], ['0x03db1a8b26d08df23337e9276a36b474510f0023'])
.get()
diff --git a/src/routes/safe/store/test/safe.reducer.js b/src/routes/safe/store/test/safe.reducer.js
index c9c241df..dea0bfbd 100644
--- a/src/routes/safe/store/test/safe.reducer.js
+++ b/src/routes/safe/store/test/safe.reducer.js
@@ -23,27 +23,31 @@ const aStore = (initState) => {
const providerReducerTests = () => {
describe('Safe Actions[addSafe]', () => {
let store
+ let address
+ let formValues
beforeEach(() => {
store = aStore()
- })
-
- it('reducer should return SafeRecord from form values', () => {
- // GIVEN
- const address = '0x03db1a8b26d08df23337e9276a36b474510f0025'
- const formValues = {
+ address = '0x03db1a8b26d08df23337e9276a36b474510f0025'
+ formValues = {
[SafeFields.FIELD_NAME]: 'Adol ICO Safe',
[SafeFields.FIELD_CONFIRMATIONS]: 1,
[SafeFields.FIELD_OWNERS]: 1,
+ [SafeFields.FIELD_DAILY_LIMIT]: 10,
[SafeFields.getOwnerAddressBy(0)]: '0x03db1a8b26d08df23337e9276a36b474510f0023',
[SafeFields.getOwnerNameBy(0)]: 'Adol Metamask',
address,
}
+ })
+
+ it('reducer should return SafeRecord from form values', () => {
+ // GIVEN in beforeEach method
// WHEN
store.dispatch(addSafe(
formValues[SafeFields.FIELD_NAME],
formValues.address,
formValues[SafeFields.FIELD_CONFIRMATIONS],
+ formValues[SafeFields.FIELD_DAILY_LIMIT],
getNamesFrom(formValues),
getAccountsFrom(formValues),
))
@@ -54,22 +58,14 @@ const providerReducerTests = () => {
})
it('reducer loads information from localStorage', async () => {
- // GIVEN
- const address = '0x03db1a8b26d08df23337e9276a36b474510f0025'
- const formValues = {
- [SafeFields.FIELD_NAME]: 'Adol ICO Safe',
- [SafeFields.FIELD_CONFIRMATIONS]: 1,
- [SafeFields.FIELD_OWNERS]: 1,
- [SafeFields.getOwnerAddressBy(0)]: '0x03db1a8b26d08df23337e9276a36b474510f0023',
- [SafeFields.getOwnerNameBy(0)]: 'Adol Metamask',
- address,
- }
+ // GIVEN in beforeEach method
// WHEN
store.dispatch(addSafe(
formValues[SafeFields.FIELD_NAME],
formValues.address,
formValues[SafeFields.FIELD_CONFIRMATIONS],
+ formValues[SafeFields.FIELD_DAILY_LIMIT],
getNamesFrom(formValues),
getAccountsFrom(formValues),
))
diff --git a/src/routes/safeList/components/SafeTable.jsx b/src/routes/safeList/components/SafeTable.jsx
index 9b1c97d8..ed7e825c 100644
--- a/src/routes/safeList/components/SafeTable.jsx
+++ b/src/routes/safeList/components/SafeTable.jsx
@@ -19,6 +19,7 @@ const SafeTable = ({ safes }: Props) => (
Deployed Address
Confirmations
Number of owners
+ Daily Limit
@@ -29,10 +30,11 @@ const SafeTable = ({ safes }: Props) => (
- {safe.name}
- {safe.address}
- {safe.confirmations}
- {safe.owners.count()}
+ {safe.get('name')}
+ {safe.get('address')}
+ {safe.get('confirmations')}
+ {safe.get('owners').count()}
+ {`${safe.get('dailyLimit')} ETH`}
))}