WA-521 Refactor ethereum modules under logic folder
This commit is contained in:
parent
933b93f5e1
commit
be9bdd25c1
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { fetchProvider } from '~/wallets/store/actions'
|
import { fetchProvider } from '~/logic/wallets/store/actions'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
fetchProvider,
|
fetchProvider,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { providerNameSelector } from '~/wallets/store/selectors/index'
|
import { providerNameSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export default createStructuredSelector({
|
export default createStructuredSelector({
|
||||||
provider: providerNameSelector,
|
provider: providerNameSelector,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
|
||||||
import { type FieldValidator } from 'final-form'
|
import { type FieldValidator } from 'final-form'
|
||||||
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
|
||||||
type Field = boolean | string | null | typeof undefined
|
type Field = boolean | string | null | typeof undefined
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
// @flow
|
||||||
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
import { getGnosisSafeContract, getCreateDailyLimitExtensionContract } from '~/logic/contracts/safeContracts'
|
||||||
|
import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit'
|
||||||
|
|
||||||
|
export const LIMIT_POSITION = 0
|
||||||
|
export const SPENT_TODAY_POS = 1
|
||||||
|
|
||||||
|
|
||||||
|
export const getDailyLimitModuleFrom = async (safeAddress: string) => {
|
||||||
|
const web3 = getWeb3()
|
||||||
|
const gnosisSafe = getGnosisSafeContract(web3).at(safeAddress)
|
||||||
|
|
||||||
|
const modules = await gnosisSafe.getModules()
|
||||||
|
const dailyAddress = modules[0]
|
||||||
|
|
||||||
|
const dailyLimitModule = getCreateDailyLimitExtensionContract(web3).at(dailyAddress)
|
||||||
|
if (await dailyLimitModule.manager.call() !== gnosisSafe.address) {
|
||||||
|
throw new Error('Using an extension of different safe')
|
||||||
|
}
|
||||||
|
|
||||||
|
return dailyLimitModule
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDailyLimitFrom = async (safeAddress: string, tokenAddress: number): Promise<DailyLimitProps> => {
|
||||||
|
const web3 = getWeb3()
|
||||||
|
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
||||||
|
|
||||||
|
const dailyLimitEth = await dailyLimitModule.dailyLimits(tokenAddress)
|
||||||
|
|
||||||
|
const limit = web3.fromWei(dailyLimitEth[LIMIT_POSITION].valueOf(), 'ether').toString()
|
||||||
|
const spentToday = web3.fromWei(dailyLimitEth[SPENT_TODAY_POS].valueOf(), 'ether').toString()
|
||||||
|
|
||||||
|
return { value: Number(limit), spentToday: Number(spentToday) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDailyLimitAddress = async (safeAddress: string) => {
|
||||||
|
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
||||||
|
|
||||||
|
return dailyLimitModule.address
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getEditDailyLimitData = async (safeAddress: string, token: number, dailyLimit: number) => {
|
||||||
|
const web3 = getWeb3()
|
||||||
|
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
||||||
|
const dailyLimitInWei = web3.toWei(dailyLimit, 'ether')
|
||||||
|
return dailyLimitModule.contract.changeDailyLimit.getData(token, dailyLimitInWei)
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
import contract from 'truffle-contract'
|
import contract from 'truffle-contract'
|
||||||
import { ensureOnce } from '~/utils/singleton'
|
import { ensureOnce } from '~/utils/singleton'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import GnosisSafeSol from '#/GnosisSafeTeamEdition.json'
|
import GnosisSafeSol from '#/GnosisSafeTeamEdition.json'
|
||||||
import ProxyFactorySol from '#/ProxyFactory.json'
|
import ProxyFactorySol from '#/ProxyFactory.json'
|
||||||
import CreateAndAddModules from '#/CreateAndAddModules.json'
|
import CreateAndAddModules from '#/CreateAndAddModules.json'
|
||||||
import DailyLimitModule from '#/DailyLimitModule.json'
|
import DailyLimitModule from '#/DailyLimitModule.json'
|
||||||
import { calculateGasOf, calculateGasPrice, EMPTY_DATA } from '~/wallets/ethTransactions'
|
import { calculateGasOf, calculateGasPrice, EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
|
|
||||||
let proxyFactoryMaster
|
let proxyFactoryMaster
|
||||||
let createAndAddModuleMaster
|
let createAndAddModuleMaster
|
|
@ -1,7 +1,8 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getSafeEthereumInstance } from '~/wallets/createTransactions'
|
import { calculateGasOf, checkReceiptStatus, calculateGasPrice } from '~/logic/wallets/ethTransactions'
|
||||||
import { calculateGasOf, checkReceiptStatus, calculateGasPrice } from '~/wallets/ethTransactions'
|
import { type Operation, submitOperation } from '~/logic/safe/safeTxHistory'
|
||||||
import { type Operation, submitOperation } from '~/wallets/safeTxHistory'
|
import { getDailyLimitModuleFrom } from '~/logic/contracts/dailyLimitContracts'
|
||||||
|
import { getSafeEthereumInstance } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
|
||||||
export const approveTransaction = async (
|
export const approveTransaction = async (
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
|
@ -52,3 +53,25 @@ export const executeTransaction = async (
|
||||||
|
|
||||||
return txHash
|
return txHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const executeDailyLimit = async (
|
||||||
|
safeAddress: string,
|
||||||
|
to: string,
|
||||||
|
valueInWei: number,
|
||||||
|
sender: string,
|
||||||
|
) => {
|
||||||
|
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
||||||
|
const dailyLimitData = dailyLimitModule.contract.executeDailyLimit.getData(0, to, valueInWei)
|
||||||
|
const gas = await calculateGasOf(dailyLimitData, sender, dailyLimitModule.address)
|
||||||
|
const gasPrice = await calculateGasPrice()
|
||||||
|
|
||||||
|
const txHash = await dailyLimitModule.executeDailyLimit(0, to, valueInWei, { from: sender, gas, gasPrice })
|
||||||
|
checkReceiptStatus(txHash.tx)
|
||||||
|
|
||||||
|
const nonce = Date.now()
|
||||||
|
const operation = 0 // CALL for all currencies
|
||||||
|
const data = '' // empty for ETH
|
||||||
|
await submitOperation(safeAddress, to, valueInWei, data, operation, nonce, txHash, sender, 'execution')
|
||||||
|
|
||||||
|
return txHash
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
// @flow
|
||||||
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
|
import { executeDailyLimit, executeTransaction, approveTransaction } from '~/logic/safe/safeBlockchainOperations'
|
||||||
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/WithdrawForm'
|
||||||
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
|
import { getGnosisSafeContract } from '~/logic/contracts/safeContracts'
|
||||||
|
|
||||||
|
export const TX_NAME_PARAM = 'txName'
|
||||||
|
export const TX_DESTINATION_PARAM = 'txDestination'
|
||||||
|
export const TX_VALUE_PARAM = 'txValue'
|
||||||
|
|
||||||
|
export const EXECUTED_CONFIRMATION_HASH = 'EXECUTED'
|
||||||
|
|
||||||
|
const hasOneOwner = (safe: Safe) => {
|
||||||
|
const owners = safe.get('owners')
|
||||||
|
if (!owners) {
|
||||||
|
throw new Error('Received a Safe without owners when creating a tx')
|
||||||
|
}
|
||||||
|
|
||||||
|
return owners.count() === 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSafeEthereumInstance = async (safeAddress: string) => {
|
||||||
|
const web3 = getWeb3()
|
||||||
|
const GnosisSafe = await getGnosisSafeContract(web3)
|
||||||
|
return GnosisSafe.at(safeAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createTransaction = async (
|
||||||
|
safe: Safe,
|
||||||
|
name: string,
|
||||||
|
to: string,
|
||||||
|
value: number,
|
||||||
|
nonce: number,
|
||||||
|
sender: string,
|
||||||
|
data: string = EMPTY_DATA,
|
||||||
|
) => {
|
||||||
|
const web3 = getWeb3()
|
||||||
|
const safeAddress = safe.get('address')
|
||||||
|
const threshold = safe.get('threshold')
|
||||||
|
const valueInWei = web3.toWei(value, 'ether')
|
||||||
|
const CALL = 0
|
||||||
|
|
||||||
|
const isExecution = hasOneOwner(safe) || threshold === 1
|
||||||
|
|
||||||
|
return isExecution
|
||||||
|
? executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
|
||||||
|
: approveTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const processTransaction = async (
|
||||||
|
safeAddress: string,
|
||||||
|
tx: Transaction,
|
||||||
|
alreadyConfirmed: number,
|
||||||
|
sender: string,
|
||||||
|
threshold: number,
|
||||||
|
) => {
|
||||||
|
const web3 = getWeb3()
|
||||||
|
const nonce = tx.get('nonce')
|
||||||
|
const valueInWei = web3.toWei(tx.get('value'), 'ether')
|
||||||
|
const to = tx.get('destination')
|
||||||
|
const data = tx.get('data')
|
||||||
|
const CALL = 0
|
||||||
|
|
||||||
|
const thresholdReached = threshold === alreadyConfirmed + 1
|
||||||
|
return thresholdReached
|
||||||
|
? executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
|
||||||
|
: approveTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const withdraw = async (values: Object, safe: Safe, sender: string): Promise<void> => {
|
||||||
|
const safeAddress = safe.get('address')
|
||||||
|
const destination = values[DESTINATION_PARAM]
|
||||||
|
const valueInEth = values[VALUE_PARAM]
|
||||||
|
const valueInWei = getWeb3().toWei(valueInEth, 'ether')
|
||||||
|
|
||||||
|
// TODO write subject `Withdraw movement of ${valueInEth}`
|
||||||
|
return executeDailyLimit(safeAddress, destination, valueInWei, sender)
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getSafeEthereumInstance } from '~/wallets/createTransactions'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
|
||||||
import { getTxServiceUriFrom, getTxServiceHost } from '~/config'
|
import { getTxServiceUriFrom, getTxServiceHost } from '~/config'
|
||||||
|
import { getSafeEthereumInstance } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
|
||||||
export type TxServiceType = 'confirmation' | 'execution'
|
export type TxServiceType = 'confirmation' | 'execution' | 'initialised'
|
||||||
export type Operation = 0 | 1 | 2
|
export type Operation = 0 | 1 | 2
|
||||||
|
|
||||||
const calculateBodyFrom = async (
|
const calculateBodyFrom = async (
|
||||||
|
@ -32,6 +32,7 @@ const calculateBodyFrom = async (
|
||||||
type,
|
type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildTxServiceUrlFrom = (safeAddress: string) => {
|
export const buildTxServiceUrlFrom = (safeAddress: string) => {
|
||||||
const host = getTxServiceHost()
|
const host = getTxServiceHost()
|
||||||
const address = getWeb3().toChecksumAddress(safeAddress)
|
const address = getWeb3().toChecksumAddress(safeAddress)
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { BigNumber } from 'bignumber.js'
|
import { BigNumber } from 'bignumber.js'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { enhancedFetch } from '~/utils/fetch'
|
import { enhancedFetch } from '~/utils/fetch'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { BigNumber } from 'bignumber.js'
|
import { BigNumber } from 'bignumber.js'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import type { ProviderProps } from '~/wallets/store/model/provider'
|
import type { ProviderProps } from '~/logic/wallets/store/model/provider'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
|
|
||||||
let web3
|
let web3
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createAction } from 'redux-actions'
|
import { createAction } from 'redux-actions'
|
||||||
import { type Provider } from '~/wallets/store/model/provider'
|
import { type Provider } from '~/logic/wallets/store/model/provider'
|
||||||
|
|
||||||
export const ADD_PROVIDER = 'ADD_PROVIDER'
|
export const ADD_PROVIDER = 'ADD_PROVIDER'
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// @flow
|
// @flow
|
||||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
import { getProviderInfo } from '~/wallets/getWeb3'
|
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import type { ProviderProps } from '~/wallets/store/model/provider'
|
import type { ProviderProps } from '~/logic/wallets/store/model/provider'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
import addProvider from './addProvider'
|
import addProvider from './addProvider'
|
||||||
|
|
||||||
export const processProviderResponse = (dispatch: ReduxDispatch<*>, response: ProviderProps) => {
|
export const processProviderResponse = (dispatch: ReduxDispatch<*>, response: ProviderProps) => {
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { handleActions, type ActionType } from 'redux-actions'
|
import { handleActions, type ActionType } from 'redux-actions'
|
||||||
import { makeProvider, type Provider } from '~/wallets/store/model/provider'
|
import { makeProvider, type Provider } from '~/logic/wallets/store/model/provider'
|
||||||
import addProvider, { ADD_PROVIDER } from '~/wallets/store/actions/addProvider'
|
import addProvider, { ADD_PROVIDER } from '~/logic/wallets/store/actions/addProvider'
|
||||||
|
|
||||||
export const PROVIDER_REDUCER_ID = 'providers'
|
export const PROVIDER_REDUCER_ID = 'providers'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createSelector } from 'reselect'
|
import { createSelector } from 'reselect'
|
||||||
import type { Provider } from '~/wallets/store/model/provider'
|
import type { Provider } from '~/logic/wallets/store/model/provider'
|
||||||
import { PROVIDER_REDUCER_ID } from '~/wallets/store/reducer/provider'
|
import { PROVIDER_REDUCER_ID } from '~/logic/wallets/store/reducer/provider'
|
||||||
|
|
||||||
const providerSelector = (state: any): Provider => state[PROVIDER_REDUCER_ID]
|
const providerSelector = (state: any): Provider => state[PROVIDER_REDUCER_ID]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { PROVIDER_REDUCER_ID } from '~/wallets/store/reducer/provider'
|
import { PROVIDER_REDUCER_ID } from '~/logic/wallets/store/reducer/provider'
|
||||||
import { userAccountSelector } from '../selectors'
|
import { userAccountSelector } from '../selectors'
|
||||||
import { ProviderFactory } from './builder/index.builder'
|
import { ProviderFactory } from './builder/index.builder'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import type { Provider } from '~/wallets/store/model/provider'
|
import type { Provider } from '~/logic/wallets/store/model/provider'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
|
|
||||||
class ProviderBuilder {
|
class ProviderBuilder {
|
||||||
provider: Provider
|
provider: Provider
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { PROVIDER_REDUCER_ID } from '~/wallets/store/reducer/provider'
|
import { PROVIDER_REDUCER_ID } from '~/logic/wallets/store/reducer/provider'
|
||||||
import { providerNameSelector } from '../selectors'
|
import { providerNameSelector } from '../selectors'
|
||||||
import { ProviderFactory } from './builder/index.builder'
|
import { ProviderFactory } from './builder/index.builder'
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { combineReducers, createStore, applyMiddleware, compose } from 'redux'
|
import { combineReducers, createStore, applyMiddleware, compose } from 'redux'
|
||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk'
|
||||||
import providerReducer, { PROVIDER_REDUCER_ID } from '~/wallets/store/reducer/provider'
|
import providerReducer, { PROVIDER_REDUCER_ID } from '~/logic/wallets/store/reducer/provider'
|
||||||
import type { ProviderProps } from '~/wallets/store/model/provider'
|
import type { ProviderProps } from '~/logic/wallets/store/model/provider'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
import { processProviderResponse } from '../actions/fetchProvider'
|
import { processProviderResponse } from '../actions/fetchProvider'
|
||||||
|
|
||||||
const providerReducerTests = () => {
|
const providerReducerTests = () => {
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { BigNumber } from 'bignumber.js'
|
import { BigNumber } from 'bignumber.js'
|
||||||
|
|
||||||
export const toNative = async (amt: string | number | BigNumber, decimal: number): Promise<BigNumber> => {
|
export const toNative = async (amt: string | number | BigNumber, decimal: number): Promise<BigNumber> => {
|
|
@ -4,7 +4,7 @@ import { State, Store } from '@sambego/storybook-state'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
import styles from '~/components/layout/PageFrame/index.scss'
|
||||||
import { getAccountsFrom, getThresholdFrom } from '~/routes/open/utils/safeDataExtractor'
|
import { getAccountsFrom, getThresholdFrom } from '~/routes/open/utils/safeDataExtractor'
|
||||||
import { getProviderInfo } from '~/wallets/getWeb3'
|
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import Component from './Layout'
|
import Component from './Layout'
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from 'react'
|
||||||
import * as TestUtils from 'react-dom/test-utils'
|
import * as TestUtils from 'react-dom/test-utils'
|
||||||
import Layout from '~/routes/open/components/Layout'
|
import Layout from '~/routes/open/components/Layout'
|
||||||
import { FIELD_CONFIRMATIONS, FIELD_OWNERS } from '~/routes/open/components/fields'
|
import { FIELD_CONFIRMATIONS, FIELD_OWNERS } from '~/routes/open/components/fields'
|
||||||
import { getProviderInfo } from '~/wallets/getWeb3'
|
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import Wrapper from '~/test/utils/Wrapper'
|
import Wrapper from '~/test/utils/Wrapper'
|
||||||
import { CONFIRMATIONS_ERROR } from '~/routes/open/components/SafeForm'
|
import { CONFIRMATIONS_ERROR } from '~/routes/open/components/SafeForm'
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import * as TestUtils from 'react-dom/test-utils'
|
||||||
import GnoForm from '~/components/forms/GnoForm'
|
import GnoForm from '~/components/forms/GnoForm'
|
||||||
import { FIELD_OWNERS } from '~/routes/open/components/fields'
|
import { FIELD_OWNERS } from '~/routes/open/components/fields'
|
||||||
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
|
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
|
||||||
import { getProviderInfo } from '~/wallets/getWeb3'
|
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import Wrapper from '~/test/utils/Wrapper'
|
import Wrapper from '~/test/utils/Wrapper'
|
||||||
import { ADDRESS_REPEATED_ERROR } from '~/components/forms/validator'
|
import { ADDRESS_REPEATED_ERROR } from '~/components/forms/validator'
|
||||||
import Owners from './index'
|
import Owners from './index'
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { connect } from 'react-redux'
|
||||||
|
|
||||||
import Page from '~/components/layout/Page'
|
import Page from '~/components/layout/Page'
|
||||||
import { getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getDailyLimitFrom } from '~/routes/open/utils/safeDataExtractor'
|
import { getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getDailyLimitFrom } from '~/routes/open/utils/safeDataExtractor'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { getGnosisSafeContract, deploySafeContract, initContracts } from '~/wallets/safeContracts'
|
import { getGnosisSafeContract, deploySafeContract, initContracts } from '~/logic/contracts/safeContracts'
|
||||||
import { checkReceiptStatus } from '~/wallets/ethTransactions'
|
import { checkReceiptStatus } from '~/logic/wallets/ethTransactions'
|
||||||
import selector from './selector'
|
import selector from './selector'
|
||||||
import actions, { type Actions, type AddSafe } from './actions'
|
import actions, { type Actions, type AddSafe } from './actions'
|
||||||
import Layout from '../components/Layout'
|
import Layout from '../components/Layout'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { providerNameSelector, userAccountSelector } from '~/wallets/store/selectors/index'
|
import { providerNameSelector, userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export default createStructuredSelector({
|
export default createStructuredSelector({
|
||||||
provider: providerNameSelector,
|
provider: providerNameSelector,
|
||||||
|
|
|
@ -5,8 +5,8 @@ import Stepper from '~/components/Stepper'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { type Owner, makeOwner } from '~/routes/safe/store/model/owner'
|
import { type Owner, makeOwner } from '~/routes/safe/store/model/owner'
|
||||||
import { getSafeEthereumInstance, createTransaction } from '~/wallets/createTransactions'
|
|
||||||
import { setOwners } from '~/utils/localStorage'
|
import { setOwners } from '~/utils/localStorage'
|
||||||
|
import { getSafeEthereumInstance, createTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
import AddOwnerForm, { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from './AddOwnerForm'
|
import AddOwnerForm, { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from './AddOwnerForm'
|
||||||
import Review from './Review'
|
import Review from './Review'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Stepper from '~/components/Stepper'
|
import Stepper from '~/components/Stepper'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { createTransaction } from '~/wallets/createTransactions'
|
|
||||||
import { getEditDailyLimitData, getDailyLimitAddress } from '~/routes/safe/component/Withdraw/withdraw'
|
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
|
import { createTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
import { getEditDailyLimitData, getDailyLimitAddress } from '~/logic/contracts/dailyLimitContracts'
|
||||||
import EditDailyLimitForm, { EDIT_DAILY_LIMIT_PARAM } from './EditDailyLimitForm'
|
import EditDailyLimitForm, { EDIT_DAILY_LIMIT_PARAM } from './EditDailyLimitForm'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
import actions, { type Actions } from './actions'
|
import actions, { type Actions } from './actions'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as React from 'react'
|
||||||
import Stepper from '~/components/Stepper'
|
import Stepper from '~/components/Stepper'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { getSafeEthereumInstance, createTransaction } from '~/wallets/createTransactions'
|
import { getSafeEthereumInstance, createTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
import RemoveOwnerForm, { DECREASE_PARAM } from './RemoveOwnerForm'
|
import RemoveOwnerForm, { DECREASE_PARAM } from './RemoveOwnerForm'
|
||||||
import Review from './Review'
|
import Review from './Review'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { createStructuredSelector, createSelector } from 'reselect'
|
import { createStructuredSelector, createSelector } from 'reselect'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
import { safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
|
import { safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import ExpandLess from '@material-ui/icons/ExpandLess'
|
||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
import ExpandMore from '@material-ui/icons/ExpandMore'
|
||||||
import { type OwnerProps } from '~/routes/safe/store/model/owner'
|
import { type OwnerProps } from '~/routes/safe/store/model/owner'
|
||||||
import { type WithStyles } from '~/theme/mui'
|
import { type WithStyles } from '~/theme/mui'
|
||||||
import { sameAddress } from '~/wallets/ethAddresses'
|
import { sameAddress } from '~/logic/wallets/ethAddresses'
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
nested: {
|
nested: {
|
||||||
|
|
|
@ -7,10 +7,10 @@ import { sleep } from '~/utils/timer'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { getStandardTokenContract } from '~/routes/tokens/store/actions/fetchTokens'
|
import { getStandardTokenContract } from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
import { type Token } from '~/routes/tokens/store/model/token'
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
import { createTransaction } from '~/wallets/createTransactions'
|
|
||||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
|
||||||
import { toNative } from '~/wallets/tokens'
|
|
||||||
import { isEther } from '~/utils/tokens'
|
import { isEther } from '~/utils/tokens'
|
||||||
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
|
import { toNative } from '~/logic/wallets/tokens'
|
||||||
|
import { createTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
import actions, { type Actions } from './actions'
|
import actions, { type Actions } from './actions'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
import SendTokenForm, { TKN_DESTINATION_PARAM, TKN_VALUE_PARAM } from './SendTokenForm'
|
import SendTokenForm, { TKN_DESTINATION_PARAM, TKN_VALUE_PARAM } from './SendTokenForm'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Stepper from '~/components/Stepper'
|
import Stepper from '~/components/Stepper'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { getSafeEthereumInstance, createTransaction } from '~/wallets/createTransactions'
|
import { getSafeEthereumInstance, createTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import ThresholdForm, { THRESHOLD_PARAM } from './ThresholdForm'
|
import ThresholdForm, { THRESHOLD_PARAM } from './ThresholdForm'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Collapsed from '~/routes/safe/component/Transactions/Collapsed'
|
||||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
import Hairline from '~/components/layout/Hairline/index'
|
import Hairline from '~/components/layout/Hairline/index'
|
||||||
import Button from '~/components/layout/Button'
|
import Button from '~/components/layout/Button'
|
||||||
import { sameAddress } from '~/wallets/ethAddresses'
|
import { sameAddress } from '~/logic/wallets/ethAddresses'
|
||||||
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { confirmationsTransactionSelector } from '~/routes/safe/store/selectors/index'
|
import { confirmationsTransactionSelector } from '~/routes/safe/store/selectors/index'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { connect } from 'react-redux'
|
||||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
import NoTransactions from '~/routes/safe/component/Transactions/NoTransactions'
|
import NoTransactions from '~/routes/safe/component/Transactions/NoTransactions'
|
||||||
import GnoTransaction from '~/routes/safe/component/Transactions/Transaction'
|
import GnoTransaction from '~/routes/safe/component/Transactions/Transaction'
|
||||||
import { processTransaction } from './processTransactions'
|
import { sameAddress } from '~/logic/wallets/ethAddresses'
|
||||||
|
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
||||||
|
import { processTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
import actions, { type Actions } from './actions'
|
import actions, { type Actions } from './actions'
|
||||||
|
|
||||||
|
@ -17,10 +19,22 @@ type Props = SelectorProps & Actions & {
|
||||||
class Transactions extends React.Component<Props, {}> {
|
class Transactions extends React.Component<Props, {}> {
|
||||||
onProcessTx = async (tx: Transaction, alreadyConfirmed: number) => {
|
onProcessTx = async (tx: Transaction, alreadyConfirmed: number) => {
|
||||||
const {
|
const {
|
||||||
fetchTransactions, safeAddress, userAddress,
|
fetchTransactions, safeAddress, userAddress, threshold,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
await processTransaction(safeAddress, tx, alreadyConfirmed, userAddress)
|
const confirmations = tx.get('confirmations')
|
||||||
|
const userHasAlreadyConfirmed = confirmations.filter((confirmation: Confirmation) => {
|
||||||
|
const ownerAddress = confirmation.get('owner').get('address')
|
||||||
|
const samePerson = sameAddress(ownerAddress, userAddress)
|
||||||
|
|
||||||
|
return samePerson && confirmation.get('type') === 'confirmed'
|
||||||
|
}).count() > 0
|
||||||
|
|
||||||
|
if (userHasAlreadyConfirmed) {
|
||||||
|
throw new Error('Owner has already confirmed this transaction')
|
||||||
|
}
|
||||||
|
|
||||||
|
await processTransaction(safeAddress, tx, alreadyConfirmed, userAddress, threshold)
|
||||||
fetchTransactions()
|
fetchTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { List } from 'immutable'
|
|
||||||
import { type Owner } from '~/routes/safe/store/model/owner'
|
|
||||||
import { load, TX_KEY } from '~/utils/localStorage'
|
|
||||||
import { type Confirmation, makeConfirmation } from '~/routes/safe/store/model/confirmation'
|
|
||||||
import { makeTransaction, type Transaction, type TransactionProps } from '~/routes/safe/store/model/transaction'
|
|
||||||
import { getGnosisSafeContract } from '~/wallets/safeContracts'
|
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
|
||||||
import { sameAddress } from '~/wallets/ethAddresses'
|
|
||||||
import { EXECUTED_CONFIRMATION_HASH } from '~/wallets/createTransactions'
|
|
||||||
import { checkReceiptStatus, calculateGasOf, calculateGasPrice } from '~/wallets/ethTransactions'
|
|
||||||
|
|
||||||
export const updateTransaction = (
|
|
||||||
name: string,
|
|
||||||
nonce: number,
|
|
||||||
destination: string,
|
|
||||||
value: number,
|
|
||||||
creator: string,
|
|
||||||
confirmations: List<Confirmation>,
|
|
||||||
tx: string,
|
|
||||||
safeAddress: string,
|
|
||||||
safeThreshold: number,
|
|
||||||
data: string,
|
|
||||||
) => {
|
|
||||||
const transaction: Transaction = makeTransaction({
|
|
||||||
name, nonce, value, confirmations, destination, threshold: safeThreshold, tx, data,
|
|
||||||
})
|
|
||||||
|
|
||||||
const safeTransactions = load(TX_KEY) || {}
|
|
||||||
const transactions = safeTransactions[safeAddress]
|
|
||||||
const txsRecord = transactions ? List(transactions) : List([])
|
|
||||||
|
|
||||||
const index = txsRecord.findIndex((trans: TransactionProps) => trans.nonce === nonce)
|
|
||||||
|
|
||||||
safeTransactions[safeAddress] = txsRecord.remove(index).push(transaction)
|
|
||||||
|
|
||||||
localStorage.setItem(TX_KEY, JSON.stringify(safeTransactions))
|
|
||||||
}
|
|
||||||
|
|
||||||
const getOperation = () => 0
|
|
||||||
|
|
||||||
const execTransaction = async (
|
|
||||||
gnosisSafe: any,
|
|
||||||
destination: string,
|
|
||||||
txValue: number,
|
|
||||||
nonce: number,
|
|
||||||
executor: string,
|
|
||||||
data: string,
|
|
||||||
) => {
|
|
||||||
const CALL = getOperation()
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const valueInWei = web3.toWei(txValue, 'ether')
|
|
||||||
|
|
||||||
const txData = await gnosisSafe.contract.execTransactionIfApproved.getData(destination, valueInWei, data, CALL, nonce)
|
|
||||||
const owners = await gnosisSafe.getOwners()
|
|
||||||
const gas = await calculateGasOf(txData, executor, gnosisSafe.address) + (17000 * owners.length)
|
|
||||||
const gasPrice = await calculateGasPrice()
|
|
||||||
|
|
||||||
return gnosisSafe
|
|
||||||
.execTransactionIfApproved(destination, valueInWei, data, CALL, nonce, { from: executor, gas, gasPrice })
|
|
||||||
}
|
|
||||||
|
|
||||||
const execConfirmation = async (
|
|
||||||
gnosisSafe: any,
|
|
||||||
txDestination: string,
|
|
||||||
txValue: number,
|
|
||||||
nonce: number,
|
|
||||||
executor: string,
|
|
||||||
data: string,
|
|
||||||
) => {
|
|
||||||
const CALL = getOperation()
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const valueInWei = web3.toWei(txValue, 'ether')
|
|
||||||
const txData = await gnosisSafe.contract
|
|
||||||
.approveTransactionWithParameters.getData(txDestination, valueInWei, data, CALL, nonce)
|
|
||||||
const gas = await calculateGasOf(txData, executor, gnosisSafe.address)
|
|
||||||
const gasPrice = await calculateGasPrice()
|
|
||||||
|
|
||||||
return gnosisSafe
|
|
||||||
.approveTransactionWithParameters(txDestination, valueInWei, data, CALL, nonce, { from: executor, gas, gasPrice })
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateConfirmations = (confirmations: List<Confirmation>, userAddress: string, txHash: string) =>
|
|
||||||
confirmations.map((confirmation: Confirmation) => {
|
|
||||||
const owner: Owner = confirmation.get('owner')
|
|
||||||
const samePerson = sameAddress(owner.get('address'), userAddress)
|
|
||||||
const status: boolean = samePerson ? true : confirmation.get('status')
|
|
||||||
const hash: string = samePerson ? txHash : confirmation.get('hash')
|
|
||||||
|
|
||||||
return makeConfirmation({ owner, status, hash })
|
|
||||||
})
|
|
||||||
|
|
||||||
export const processTransaction = async (
|
|
||||||
safeAddress: string,
|
|
||||||
tx: Transaction,
|
|
||||||
alreadyConfirmed: number,
|
|
||||||
userAddress: string,
|
|
||||||
) => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const GnosisSafe = await getGnosisSafeContract(web3)
|
|
||||||
const gnosisSafe = GnosisSafe.at(safeAddress)
|
|
||||||
|
|
||||||
const confirmations = tx.get('confirmations')
|
|
||||||
const userHasAlreadyConfirmed = confirmations.filter((confirmation: Confirmation) => {
|
|
||||||
const ownerAddress = confirmation.get('owner').get('address')
|
|
||||||
const samePerson = sameAddress(ownerAddress, userAddress)
|
|
||||||
|
|
||||||
return samePerson && confirmation.get('status')
|
|
||||||
}).count() > 0
|
|
||||||
|
|
||||||
if (userHasAlreadyConfirmed) {
|
|
||||||
throw new Error('Owner has already confirmed this transaction')
|
|
||||||
}
|
|
||||||
|
|
||||||
const threshold = tx.get('threshold')
|
|
||||||
const thresholdReached = threshold === alreadyConfirmed + 1
|
|
||||||
const nonce = tx.get('nonce')
|
|
||||||
const txName = tx.get('name')
|
|
||||||
const txValue = tx.get('value')
|
|
||||||
const txDestination = tx.get('destination')
|
|
||||||
const data = tx.get('data')
|
|
||||||
|
|
||||||
const txHash = thresholdReached
|
|
||||||
? await execTransaction(gnosisSafe, txDestination, txValue, nonce, userAddress, data)
|
|
||||||
: await execConfirmation(gnosisSafe, txDestination, txValue, nonce, userAddress, data)
|
|
||||||
|
|
||||||
checkReceiptStatus(txHash.tx)
|
|
||||||
|
|
||||||
const confirmationHash =
|
|
||||||
thresholdReached ? EXECUTED_CONFIRMATION_HASH : txHash.tx
|
|
||||||
const executedConfirmations: List<Confirmation> =
|
|
||||||
updateConfirmations(tx.get('confirmations'), userAddress, confirmationHash)
|
|
||||||
|
|
||||||
return updateTransaction(
|
|
||||||
txName,
|
|
||||||
nonce,
|
|
||||||
txDestination,
|
|
||||||
txValue,
|
|
||||||
userAddress,
|
|
||||||
executedConfirmations,
|
|
||||||
thresholdReached ? txHash.tx : '',
|
|
||||||
safeAddress,
|
|
||||||
threshold,
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ import { List } from 'immutable'
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
import { safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
|
import { safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
transactions: List<Transaction>,
|
transactions: List<Transaction>,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Block from '~/components/layout/Block'
|
||||||
import Bold from '~/components/layout/Bold'
|
import Bold from '~/components/layout/Bold'
|
||||||
import Heading from '~/components/layout/Heading'
|
import Heading from '~/components/layout/Heading'
|
||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/withdraw'
|
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/WithdrawForm'
|
||||||
|
|
||||||
type FormProps = {
|
type FormProps = {
|
||||||
values: Object,
|
values: Object,
|
||||||
|
|
|
@ -5,9 +5,10 @@ import TextField from '~/components/forms/TextField'
|
||||||
import { composeValidators, inLimit, mustBeFloat, required, greaterThan, mustBeEthereumAddress } from '~/components/forms/validator'
|
import { composeValidators, inLimit, mustBeFloat, required, greaterThan, mustBeEthereumAddress } from '~/components/forms/validator'
|
||||||
import Block from '~/components/layout/Block'
|
import Block from '~/components/layout/Block'
|
||||||
import Heading from '~/components/layout/Heading'
|
import Heading from '~/components/layout/Heading'
|
||||||
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/withdraw'
|
|
||||||
|
|
||||||
export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
|
export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
|
||||||
|
export const DESTINATION_PARAM = 'destination'
|
||||||
|
export const VALUE_PARAM = 'ether'
|
||||||
|
|
||||||
export const safeFieldsValidation = (values: Object) => {
|
export const safeFieldsValidation = (values: Object) => {
|
||||||
const errors = {}
|
const errors = {}
|
||||||
|
|
|
@ -4,8 +4,8 @@ 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 { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
|
import { withdraw } from '~/logic/safe/safeFrontendOperations'
|
||||||
import selector, { type SelectorProps } from './selector'
|
import selector, { type SelectorProps } from './selector'
|
||||||
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'
|
import actions, { type Actions } from './actions'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { List } from 'immutable'
|
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
|
||||||
import { getGnosisSafeContract, getCreateDailyLimitExtensionContract } from '~/wallets/safeContracts'
|
|
||||||
import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit'
|
|
||||||
import { checkReceiptStatus, calculateGasOf, calculateGasPrice, EMPTY_DATA } from '~/wallets/ethTransactions'
|
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
|
||||||
import { buildExecutedConfirmationFrom, storeTransaction } from '~/wallets/createTransactions'
|
|
||||||
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
|
||||||
|
|
||||||
export const LIMIT_POSITION = 0
|
|
||||||
export const SPENT_TODAY_POS = 1
|
|
||||||
export const DESTINATION_PARAM = 'destination'
|
|
||||||
export const VALUE_PARAM = 'ether'
|
|
||||||
|
|
||||||
const getDailyLimitModuleFrom = async (safeAddress) => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const gnosisSafe = getGnosisSafeContract(web3).at(safeAddress)
|
|
||||||
|
|
||||||
const modules = await gnosisSafe.getModules()
|
|
||||||
const dailyAddress = modules[0]
|
|
||||||
|
|
||||||
const dailyLimitModule = getCreateDailyLimitExtensionContract(web3).at(dailyAddress)
|
|
||||||
if (await dailyLimitModule.manager.call() !== gnosisSafe.address) {
|
|
||||||
throw new Error('Using an extension of different safe')
|
|
||||||
}
|
|
||||||
|
|
||||||
return dailyLimitModule
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDailyLimitFrom = async (safeAddress: string, tokenAddress: number): Promise<DailyLimitProps> => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
|
||||||
|
|
||||||
const dailyLimitEth = await dailyLimitModule.dailyLimits(tokenAddress)
|
|
||||||
|
|
||||||
const limit = web3.fromWei(dailyLimitEth[LIMIT_POSITION].valueOf(), 'ether').toString()
|
|
||||||
const spentToday = web3.fromWei(dailyLimitEth[SPENT_TODAY_POS].valueOf(), 'ether').toString()
|
|
||||||
|
|
||||||
return { value: Number(limit), spentToday: Number(spentToday) }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDailyLimitAddress = async (safeAddress: string) => {
|
|
||||||
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
|
||||||
|
|
||||||
return dailyLimitModule.address
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getEditDailyLimitData = async (safeAddress: string, token: number, dailyLimit: number) => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
|
||||||
const dailyLimitInWei = web3.toWei(dailyLimit, 'ether')
|
|
||||||
return dailyLimitModule.contract.changeDailyLimit.getData(token, dailyLimitInWei)
|
|
||||||
}
|
|
||||||
|
|
||||||
const withdraw = async (values: Object, safe: Safe, userAccount: string): Promise<void> => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const safeAddress = safe.get('address')
|
|
||||||
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
|
|
||||||
|
|
||||||
const destination = values[DESTINATION_PARAM]
|
|
||||||
const valueInEth = values[VALUE_PARAM]
|
|
||||||
const value = web3.toWei(valueInEth, 'ether')
|
|
||||||
|
|
||||||
const dailyLimitData = dailyLimitModule.contract.executeDailyLimit.getData(0, destination, value)
|
|
||||||
const gas = await calculateGasOf(dailyLimitData, userAccount, dailyLimitModule.address)
|
|
||||||
const gasPrice = await calculateGasPrice()
|
|
||||||
|
|
||||||
const txHash = await dailyLimitModule.executeDailyLimit(0, destination, value, { from: userAccount, gas, gasPrice })
|
|
||||||
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'), EMPTY_DATA)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withdraw
|
|
|
@ -2,11 +2,11 @@
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { createSelector, createStructuredSelector, type Selector } from 'reselect'
|
import { createSelector, createStructuredSelector, type Selector } from 'reselect'
|
||||||
import { safeSelector, type RouterProps, type SafeSelectorProps } from '~/routes/safe/store/selectors'
|
import { safeSelector, type RouterProps, type SafeSelectorProps } from '~/routes/safe/store/selectors'
|
||||||
import { providerNameSelector, userAccountSelector } from '~/wallets/store/selectors/index'
|
import { providerNameSelector, userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { type Owner } from '~/routes/safe/store/model/owner'
|
import { type Owner } from '~/routes/safe/store/model/owner'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
import { sameAddress } from '~/wallets/ethAddresses'
|
import { sameAddress } from '~/logic/wallets/ethAddresses'
|
||||||
import { activeTokensSelector } from '~/routes/tokens/store/selectors'
|
import { activeTokensSelector } from '~/routes/tokens/store/selectors'
|
||||||
import { type Token } from '~/routes/tokens/store/model/token'
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@ import { type GlobalState } from '~/store/index'
|
||||||
import { makeOwner } from '~/routes/safe/store/model/owner'
|
import { makeOwner } from '~/routes/safe/store/model/owner'
|
||||||
import { type SafeProps, type Safe, makeSafe } from '~/routes/safe/store/model/safe'
|
import { type SafeProps, type Safe, makeSafe } from '~/routes/safe/store/model/safe'
|
||||||
import { makeDailyLimit } from '~/routes/safe/store/model/dailyLimit'
|
import { makeDailyLimit } from '~/routes/safe/store/model/dailyLimit'
|
||||||
import { getDailyLimitFrom } from '~/routes/safe/component/Withdraw/withdraw'
|
|
||||||
import { getGnosisSafeInstanceAt } from '~/wallets/safeContracts'
|
|
||||||
import updateSafe from '~/routes/safe/store/actions/updateSafe'
|
import updateSafe from '~/routes/safe/store/actions/updateSafe'
|
||||||
import { getOwners } from '~/utils/localStorage'
|
import { getOwners } from '~/utils/localStorage'
|
||||||
|
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
|
import { getDailyLimitFrom } from '~/logic/contracts/dailyLimitContracts'
|
||||||
|
|
||||||
const buildOwnersFrom = (safeOwners: string[], storedOwners: Map<string, string>) => (
|
const buildOwnersFrom = (safeOwners: string[], storedOwners: Map<string, string>) => (
|
||||||
safeOwners.map((ownerAddress: string) => {
|
safeOwners.map((ownerAddress: string) => {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { makeTransaction, type Transaction } from '~/routes/safe/store/model/tra
|
||||||
import { load, TX_KEY } from '~/utils/localStorage'
|
import { load, TX_KEY } from '~/utils/localStorage'
|
||||||
import { makeConfirmation } from '~/routes/safe/store/model/confirmation'
|
import { makeConfirmation } from '~/routes/safe/store/model/confirmation'
|
||||||
import { loadSafeSubjects } from '~/utils/localStorage/transactions'
|
import { loadSafeSubjects } from '~/utils/localStorage/transactions'
|
||||||
import { buildTxServiceUrlFrom, type TxServiceType } from '~/wallets/safeTxHistory'
|
import { buildTxServiceUrlFrom, type TxServiceType } from '~/logic/safe/safeTxHistory'
|
||||||
import { enhancedFetch } from '~/utils/fetch'
|
import { enhancedFetch } from '~/utils/fetch'
|
||||||
import addTransactions from './addTransactions'
|
import addTransactions from './addTransactions'
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { Record } from 'immutable'
|
import { Record } from 'immutable'
|
||||||
import type { RecordFactory, RecordOf } from 'immutable'
|
import type { RecordFactory, RecordOf } from 'immutable'
|
||||||
import { makeOwner, type Owner } from '~/routes/safe/store/model/owner'
|
import { makeOwner, type Owner } from '~/routes/safe/store/model/owner'
|
||||||
import { type TxServiceType } from '~/wallets/safeTxHistory'
|
import { type TxServiceType } from '~/logic/safe/safeTxHistory'
|
||||||
|
|
||||||
export type ConfirmationProps = {
|
export type ConfirmationProps = {
|
||||||
owner: Owner,
|
owner: Owner,
|
||||||
|
@ -12,7 +12,7 @@ export type ConfirmationProps = {
|
||||||
|
|
||||||
export const makeConfirmation: RecordFactory<ConfirmationProps> = Record({
|
export const makeConfirmation: RecordFactory<ConfirmationProps> = Record({
|
||||||
owner: makeOwner(),
|
owner: makeOwner(),
|
||||||
type: 'confirmation',
|
type: 'initialised',
|
||||||
hash: '',
|
hash: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,13 @@ import { DEPLOYED_COMPONENT_ID } from '~/routes/open/components/FormConfirmation
|
||||||
import Open from '~/routes/open/container/Open'
|
import Open from '~/routes/open/container/Open'
|
||||||
import { history, type GlobalState } from '~/store'
|
import { history, type GlobalState } from '~/store'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import { getProviderInfo, getWeb3 } from '~/wallets/getWeb3'
|
import { getProviderInfo, getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import addProvider from '~/wallets/store/actions/addProvider'
|
import addProvider from '~/logic/wallets/store/actions/addProvider'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
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'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
|
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/WithdrawForm'
|
||||||
|
import { withdraw } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
|
||||||
export const renderSafe = async (localStore: Store<GlobalState>) => {
|
export const renderSafe = async (localStore: Store<GlobalState>) => {
|
||||||
const provider = await getProviderInfo()
|
const provider = await getProviderInfo()
|
||||||
|
|
|
@ -5,9 +5,9 @@ import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
||||||
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
|
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
|
||||||
import { getProviderInfo } from '~/wallets/getWeb3'
|
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import { grantedSelector } from '~/routes/safe/container/selector'
|
import { grantedSelector } from '~/routes/safe/container/selector'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
|
|
||||||
const grantedSelectorTests = () => {
|
const grantedSelectorTests = () => {
|
||||||
let provider
|
let provider
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/*
|
/*
|
||||||
import { aNewStore } from '~/store'
|
import { aNewStore } from '~/store'
|
||||||
import { aDeployedSafe } from '~/routes/safe/store/test/builder/deployedSafe.builder'
|
import { aDeployedSafe } from '~/routes/safe/store/test/builder/deployedSafe.builder'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import { type Match } from 'react-router-dom'
|
import { type Match } from 'react-router-dom'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { safesByOwnerSelector } from '~/routes/safeList/store/selectors'
|
import { safesByOwnerSelector } from '~/routes/safeList/store/selectors'
|
||||||
import { providerNameSelector } from '~/wallets/store/selectors/index'
|
import { providerNameSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export default createStructuredSelector({
|
export default createStructuredSelector({
|
||||||
safes: safesByOwnerSelector,
|
safes: safesByOwnerSelector,
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { List, Map } from 'immutable'
|
||||||
import { createSelector, type Selector } from 'reselect'
|
import { createSelector, type Selector } from 'reselect'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { userAccountSelector } from '~/wallets/store/selectors/index'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
import { type Owner } from '~/routes/safe/store/model/owner'
|
import { type Owner } from '~/routes/safe/store/model/owner'
|
||||||
import { sameAddress } from '~/wallets/ethAddresses'
|
import { sameAddress } from '~/logic/wallets/ethAddresses'
|
||||||
|
|
||||||
export const safesMapSelector = (state: GlobalState): Map<string, Safe> => state.safes
|
export const safesMapSelector = (state: GlobalState): Map<string, Safe> => state.safes
|
||||||
const safesListSelector: Selector<GlobalState, {}, List<Safe>> = createSelector(
|
const safesListSelector: Selector<GlobalState, {}, List<Safe>> = createSelector(
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
import { List, Map } from 'immutable'
|
import { List, Map } from 'immutable'
|
||||||
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
|
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { getProviderInfo } from '~/wallets/getWeb3'
|
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
||||||
import { PROVIDER_REDUCER_ID } from '~/wallets/store/reducer/provider'
|
import { PROVIDER_REDUCER_ID } from '~/logic/wallets/store/reducer/provider'
|
||||||
import { makeProvider, type Provider } from '~/wallets/store/model/provider'
|
import { makeProvider, type Provider } from '~/logic/wallets/store/model/provider'
|
||||||
import { safesByOwnerSelector } from '../selectors'
|
import { safesByOwnerSelector } from '../selectors'
|
||||||
|
|
||||||
const safesListSelectorTests = () => {
|
const safesListSelectorTests = () => {
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { composeValidators, required, mustBeEthereumAddress, uniqueAddress } fro
|
||||||
import Block from '~/components/layout/Block'
|
import Block from '~/components/layout/Block'
|
||||||
import Heading from '~/components/layout/Heading'
|
import Heading from '~/components/layout/Heading'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
import { getStandardTokenContract } from '~/routes/tokens/store/actions/fetchTokens'
|
import { getStandardTokenContract } from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -6,9 +6,9 @@ import FirstPage, { TOKEN_ADRESS_PARAM } from '~/routes/tokens/component/AddToke
|
||||||
import SecondPage, { TOKEN_SYMBOL_PARAM, TOKEN_DECIMALS_PARAM, TOKEN_LOGO_URL_PARAM, TOKEN_NAME_PARAM } from '~/routes/tokens/component/AddToken/SecondPage'
|
import SecondPage, { TOKEN_SYMBOL_PARAM, TOKEN_DECIMALS_PARAM, TOKEN_LOGO_URL_PARAM, TOKEN_NAME_PARAM } from '~/routes/tokens/component/AddToken/SecondPage'
|
||||||
import { makeToken, type Token } from '~/routes/tokens/store/model/token'
|
import { makeToken, type Token } from '~/routes/tokens/store/model/token'
|
||||||
import addTokenAction from '~/routes/tokens/store/actions/addToken'
|
import addTokenAction from '~/routes/tokens/store/actions/addToken'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
import Review from './Review'
|
import Review from './Review'
|
||||||
|
|
||||||
export const getSteps = () => [
|
export const getSteps = () => [
|
||||||
|
|
|
@ -4,7 +4,7 @@ import contract from 'truffle-contract'
|
||||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/StandardToken.json'
|
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/StandardToken.json'
|
||||||
import HumanFriendlyToken from '@gnosis.pm/util-contracts/build/contracts/HumanFriendlyToken.json'
|
import HumanFriendlyToken from '@gnosis.pm/util-contracts/build/contracts/HumanFriendlyToken.json'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
import { makeToken, type Token, type TokenProps } from '~/routes/tokens/store/model/token'
|
import { makeToken, type Token, type TokenProps } from '~/routes/tokens/store/model/token'
|
||||||
import { ensureOnce } from '~/utils/singleton'
|
import { ensureOnce } from '~/utils/singleton'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { createStructuredSelector } from 'reselect'
|
import { createStructuredSelector } from 'reselect'
|
||||||
import { providerNameSelector } from '~/wallets/store/selectors/index'
|
import { providerNameSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
|
||||||
export default createStructuredSelector({
|
export default createStructuredSelector({
|
||||||
provider: providerNameSelector,
|
provider: providerNameSelector,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { createBrowserHistory } from 'history'
|
||||||
import { routerMiddleware, routerReducer } from 'react-router-redux'
|
import { routerMiddleware, routerReducer } from 'react-router-redux'
|
||||||
import { combineReducers, createStore, applyMiddleware, compose, type Reducer, type Store } from 'redux'
|
import { combineReducers, createStore, applyMiddleware, compose, type Reducer, type Store } from 'redux'
|
||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk'
|
||||||
import provider, { PROVIDER_REDUCER_ID, type State as ProviderState } from '~/wallets/store/reducer/provider'
|
import provider, { PROVIDER_REDUCER_ID, type State as ProviderState } from '~/logic/wallets/store/reducer/provider'
|
||||||
import safe, { SAFE_REDUCER_ID, type State as SafeState } from '~/routes/safe/store/reducer/safe'
|
import safe, { SAFE_REDUCER_ID, type State as SafeState } from '~/routes/safe/store/reducer/safe'
|
||||||
import tokens, { TOKEN_REDUCER_ID, type State as TokensState } from '~/routes/tokens/store/reducer/tokens'
|
import tokens, { TOKEN_REDUCER_ID, type State as TokensState } from '~/routes/tokens/store/reducer/tokens'
|
||||||
import transactions, { type State as TransactionsState, transactionsInitialState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
import transactions, { type State as TransactionsState, transactionsInitialState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
||||||
|
|
|
@ -4,7 +4,7 @@ import TestUtils from 'react-dom/test-utils'
|
||||||
import SafeView from '~/routes/safe/component/Safe'
|
import SafeView from '~/routes/safe/component/Safe'
|
||||||
import { aNewStore, type GlobalState } from '~/store'
|
import { aNewStore, type GlobalState } from '~/store'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { addEtherTo } from '~/test/utils/tokenMovements'
|
import { addEtherTo } from '~/test/utils/tokenMovements'
|
||||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { ConnectedRouter } from 'react-router-redux'
|
||||||
import AppRoutes from '~/routes'
|
import AppRoutes from '~/routes'
|
||||||
import { SAFELIST_ADDRESS, SETTINS_ADDRESS } from '~/routes/routes'
|
import { SAFELIST_ADDRESS, SETTINS_ADDRESS } from '~/routes/routes'
|
||||||
import { history, type GlobalState } from '~/store'
|
import { history, type GlobalState } from '~/store'
|
||||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
|
|
||||||
export const EXPAND_BALANCE_INDEX = 0
|
export const EXPAND_BALANCE_INDEX = 0
|
||||||
export const EXPAND_OWNERS_INDEX = 1
|
export const EXPAND_OWNERS_INDEX = 1
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
import { makeSafe, type Safe } from '~/routes/safe/store/model/safe'
|
import { makeSafe, type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { buildOwnersFrom, buildDailyLimitFrom } from '~/routes/safe/store/actions'
|
import { buildOwnersFrom, buildDailyLimitFrom } from '~/routes/safe/store/actions'
|
||||||
import { FIELD_NAME, FIELD_CONFIRMATIONS, FIELD_OWNERS, getOwnerNameBy, getOwnerAddressBy, FIELD_DAILY_LIMIT } from '~/routes/open/components/fields'
|
import { FIELD_NAME, FIELD_CONFIRMATIONS, FIELD_OWNERS, getOwnerNameBy, getOwnerAddressBy, FIELD_DAILY_LIMIT } from '~/routes/open/components/fields'
|
||||||
import { getWeb3, getProviderInfo } from '~/wallets/getWeb3'
|
import { getWeb3, getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import addSafe from '~/routes/safe/store/actions/addSafe'
|
import addSafe from '~/routes/safe/store/actions/addSafe'
|
||||||
import { createSafe, type OpenState } from '~/routes/open/container/Open'
|
import { createSafe, type OpenState } from '~/routes/open/container/Open'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
import addProvider from '~/wallets/store/actions/addProvider'
|
import addProvider from '~/logic/wallets/store/actions/addProvider'
|
||||||
|
|
||||||
class SafeBuilder {
|
class SafeBuilder {
|
||||||
safe: Safe
|
safe: Safe
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { DEPLOYED_COMPONENT_ID } from '~/routes/open/components/FormConfirmation
|
||||||
import Open from '~/routes/open/container/Open'
|
import Open from '~/routes/open/container/Open'
|
||||||
import { aNewStore, history, type GlobalState } from '~/store'
|
import { aNewStore, history, type GlobalState } from '~/store'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import { getProviderInfo, getWeb3 } from '~/wallets/getWeb3'
|
import { getProviderInfo, getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import addProvider from '~/wallets/store/actions/addProvider'
|
import addProvider from '~/logic/wallets/store/actions/addProvider'
|
||||||
import { makeProvider } from '~/wallets/store/model/provider'
|
import { makeProvider } from '~/logic/wallets/store/model/provider'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
|
|
||||||
const fillOpenSafeForm = async (localStore: Store<GlobalState>) => {
|
const fillOpenSafeForm = async (localStore: Store<GlobalState>) => {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
import { addTknTo, getFirstTokenContract } from '~/test/utils/tokenMovements'
|
import { addTknTo, getFirstTokenContract } from '~/test/utils/tokenMovements'
|
||||||
import { EXPAND_BALANCE_INDEX, travelToSafe } from '~/test/builder/safe.dom.utils'
|
import { EXPAND_BALANCE_INDEX, travelToSafe } from '~/test/builder/safe.dom.utils'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { sendMoveTokensForm, dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
|
import { sendMoveTokensForm, dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { sendAddOwnerForm, checkMinedAddOwnerTx, checkPendingAddOwnerTx } from '
|
||||||
import { sendRemoveOwnerForm, checkMinedRemoveOwnerTx, checkPendingRemoveOwnerTx } from '~/test/utils/transactions/removeOwner.helper'
|
import { sendRemoveOwnerForm, checkMinedRemoveOwnerTx, checkPendingRemoveOwnerTx } from '~/test/utils/transactions/removeOwner.helper'
|
||||||
import { checkMinedThresholdTx, sendChangeThresholdForm, checkThresholdOf } from '~/test/utils/transactions/threshold.helper'
|
import { checkMinedThresholdTx, sendChangeThresholdForm, checkThresholdOf } from '~/test/utils/transactions/threshold.helper'
|
||||||
import { sendWithdrawForm, checkMinedWithdrawTx } from '~/test/utils/transactions/withdraw.helper'
|
import { sendWithdrawForm, checkMinedWithdrawTx } from '~/test/utils/transactions/withdraw.helper'
|
||||||
import { processTransaction } from '~/routes/safe/component/Transactions/processTransactions'
|
|
||||||
import { checkBalanceOf } from '~/test/utils/tokenMovements'
|
import { checkBalanceOf } from '~/test/utils/tokenMovements'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
|
import { processTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
|
||||||
describe('DOM > Feature > SAFE MULTISIG Transactions', () => {
|
describe('DOM > Feature > SAFE MULTISIG Transactions', () => {
|
||||||
let domSafe: DomSafe
|
let domSafe: DomSafe
|
||||||
|
@ -71,10 +71,11 @@ describe('DOM > Feature > SAFE MULTISIG Transactions', () => {
|
||||||
|
|
||||||
let transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
|
let transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
|
||||||
expect(transactions.length).toBe(7)
|
expect(transactions.length).toBe(7)
|
||||||
|
await checkThresholdOf(address, 3)
|
||||||
|
|
||||||
// WHEN... processing pending TXs
|
// WHEN... processing pending TXs
|
||||||
await processTransaction(address, transactions[4].props.transaction, 1, accounts[1])
|
await processTransaction(address, transactions[4].props.transaction, 1, accounts[1], 3)
|
||||||
await processTransaction(address, transactions[5].props.transaction, 1, accounts[1])
|
await processTransaction(address, transactions[5].props.transaction, 1, accounts[1], 3)
|
||||||
await refreshTransactions(store)
|
await refreshTransactions(store)
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
|
@ -93,14 +94,14 @@ describe('DOM > Feature > SAFE MULTISIG Transactions', () => {
|
||||||
let statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Not confirmed]', 'Adol 1 Eth Account [Confirmed]']
|
let statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Not confirmed]', 'Adol 1 Eth Account [Confirmed]']
|
||||||
await checkPendingRemoveOwnerTx(transactions[7], 3, 'Remove Owner Adol Metamask 3', statusses)
|
await checkPendingRemoveOwnerTx(transactions[7], 3, 'Remove Owner Adol Metamask 3', statusses)
|
||||||
|
|
||||||
await processTransaction(address, transactions[7].props.transaction, 1, accounts[1])
|
await processTransaction(address, transactions[7].props.transaction, 1, accounts[1], 3)
|
||||||
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]', 'Adol 1 Eth Account [Confirmed]']
|
statusses = ['Adol Metamask 3 [Not confirmed]', 'Adol Metamask 2 [Confirmed]', 'Adol 1 Eth Account [Confirmed]']
|
||||||
await checkPendingRemoveOwnerTx(transactions[7], 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[7].props.transaction, 2, accounts[2])
|
await processTransaction(address, transactions[7].props.transaction, 2, accounts[2], 3)
|
||||||
await refreshTransactions(store)
|
await refreshTransactions(store)
|
||||||
await checkThresholdOf(address, 2)
|
await checkThresholdOf(address, 2)
|
||||||
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
|
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
|
||||||
|
@ -112,7 +113,7 @@ describe('DOM > Feature > SAFE MULTISIG Transactions', () => {
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
|
transactions = TestUtils.scryRenderedComponentsWithType(SafeDom, Transaction)
|
||||||
await processTransaction(address, transactions[8].props.transaction, 1, accounts[1])
|
await processTransaction(address, transactions[8].props.transaction, 1, accounts[1], 2)
|
||||||
await checkThresholdOf(address, 1)
|
await checkThresholdOf(address, 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { aNewStore } from '~/store'
|
import { aNewStore } from '~/store'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { processTransaction } from '~/routes/safe/component/Transactions/processTransactions'
|
|
||||||
import { confirmationsTransactionSelector } from '~/routes/safe/store/selectors/index'
|
import { confirmationsTransactionSelector } from '~/routes/safe/store/selectors/index'
|
||||||
import { getTransactionFromReduxStore } from '~/routes/safe/test/testMultisig'
|
import { getTransactionFromReduxStore } from '~/routes/safe/test/testMultisig'
|
||||||
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { getGnosisSafeInstanceAt } from '~/wallets/safeContracts'
|
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/component/AddOwner/AddOwnerForm'
|
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/component/AddOwner/AddOwnerForm'
|
||||||
import { addOwner } from '~/routes/safe/component/AddOwner/index'
|
import { addOwner } from '~/routes/safe/component/AddOwner/index'
|
||||||
|
@ -15,9 +14,10 @@ import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
|
||||||
import { removeOwner, shouldDecrease, initialValuesFrom } from '~/routes/safe/component/RemoveOwner'
|
import { removeOwner, shouldDecrease, initialValuesFrom } from '~/routes/safe/component/RemoveOwner'
|
||||||
import { DECREASE_PARAM } from '~/routes/safe/component/RemoveOwner/RemoveOwnerForm/index'
|
import { DECREASE_PARAM } from '~/routes/safe/component/RemoveOwner/RemoveOwnerForm/index'
|
||||||
import { getSafeFrom } from '~/test/utils/safeHelper'
|
import { getSafeFrom } from '~/test/utils/safeHelper'
|
||||||
|
import { processTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
|
||||||
describe('React DOM TESTS > Add and remove owners', () => {
|
describe('React DOM TESTS > Add and remove owners', () => {
|
||||||
const processOwnerModification = async (store, safeAddress, executor) => {
|
const processOwnerModification = async (store, safeAddress, executor, threshold) => {
|
||||||
const tx = getTransactionFromReduxStore(store, safeAddress)
|
const tx = getTransactionFromReduxStore(store, safeAddress)
|
||||||
if (!tx) throw new Error()
|
if (!tx) throw new Error()
|
||||||
const confirmed = confirmationsTransactionSelector(store.getState(), { transaction: tx })
|
const confirmed = confirmationsTransactionSelector(store.getState(), { transaction: tx })
|
||||||
|
@ -25,7 +25,7 @@ describe('React DOM TESTS > Add and remove owners', () => {
|
||||||
expect(data).not.toBe(null)
|
expect(data).not.toBe(null)
|
||||||
expect(data).not.toBe(undefined)
|
expect(data).not.toBe(undefined)
|
||||||
expect(data).not.toBe('')
|
expect(data).not.toBe('')
|
||||||
return processTransaction(safeAddress, tx, confirmed, executor)
|
return processTransaction(safeAddress, tx, confirmed, executor, threshold)
|
||||||
}
|
}
|
||||||
|
|
||||||
const assureThresholdIs = async (gnosisSafe, threshold: number) => {
|
const assureThresholdIs = async (gnosisSafe, threshold: number) => {
|
||||||
|
@ -116,9 +116,9 @@ describe('React DOM TESTS > Add and remove owners', () => {
|
||||||
let safe = getSafeFrom(store.getState(), address)
|
let safe = getSafeFrom(store.getState(), address)
|
||||||
await removeOwner(values, safe, threshold, accounts[1], 'Adol Metamask 2', accounts[0])
|
await removeOwner(values, safe, threshold, accounts[1], 'Adol Metamask 2', accounts[0])
|
||||||
await store.dispatch(fetchTransactions())
|
await store.dispatch(fetchTransactions())
|
||||||
await processOwnerModification(store, address, accounts[1])
|
await processOwnerModification(store, address, accounts[1], 2)
|
||||||
|
|
||||||
await assureThresholdIs(gnosisSafe, 1)
|
await assureThresholdIs(gnosisSafe, 2)
|
||||||
await assureOwnersAre(gnosisSafe, accounts[0])
|
await assureOwnersAre(gnosisSafe, accounts[0])
|
||||||
|
|
||||||
await store.dispatch(fetchSafe(safe))
|
await store.dispatch(fetchSafe(safe))
|
||||||
|
@ -141,9 +141,9 @@ describe('React DOM TESTS > Add and remove owners', () => {
|
||||||
let safe = getSafeFrom(store.getState(), address)
|
let safe = getSafeFrom(store.getState(), address)
|
||||||
await removeOwner(values, safe, threshold, accounts[2], 'Adol Metamask 3', accounts[0])
|
await removeOwner(values, safe, threshold, accounts[2], 'Adol Metamask 3', accounts[0])
|
||||||
await store.dispatch(fetchTransactions())
|
await store.dispatch(fetchTransactions())
|
||||||
await processOwnerModification(store, address, accounts[1])
|
await processOwnerModification(store, address, accounts[1], 2)
|
||||||
|
|
||||||
await assureThresholdIs(gnosisSafe, 1)
|
await assureThresholdIs(gnosisSafe, 2)
|
||||||
await assureOwnersAre(gnosisSafe, accounts[0], accounts[1])
|
await assureOwnersAre(gnosisSafe, accounts[0], accounts[1])
|
||||||
|
|
||||||
await store.dispatch(fetchSafe(safe))
|
await store.dispatch(fetchSafe(safe))
|
||||||
|
@ -167,7 +167,7 @@ describe('React DOM TESTS > Add and remove owners', () => {
|
||||||
let safe = getSafeFrom(store.getState(), address)
|
let safe = getSafeFrom(store.getState(), address)
|
||||||
await removeOwner(values, safe, threshold, accounts[2], 'Adol Metamask 3', accounts[0])
|
await removeOwner(values, safe, threshold, accounts[2], 'Adol Metamask 3', accounts[0])
|
||||||
await store.dispatch(fetchTransactions())
|
await store.dispatch(fetchTransactions())
|
||||||
await processOwnerModification(store, address, accounts[1])
|
await processOwnerModification(store, address, accounts[1], 2)
|
||||||
|
|
||||||
await assureThresholdIs(gnosisSafe, 2)
|
await assureThresholdIs(gnosisSafe, 2)
|
||||||
await assureOwnersAre(gnosisSafe, accounts[0], accounts[1])
|
await assureOwnersAre(gnosisSafe, accounts[0], accounts[1])
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { getSafeEthereumInstance, createTransaction } from '~/wallets/createTransactions'
|
import { getSafeEthereumInstance, createTransaction } from '~/logic/safe/safeFrontendOperations'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { makeOwner } from '~/routes/safe/store/model/owner'
|
import { makeOwner } from '~/routes/safe/store/model/owner'
|
||||||
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
||||||
|
@ -9,7 +9,7 @@ import { aNewStore } from '~/store'
|
||||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
import { getSafeFrom } from '~/test/utils/safeHelper'
|
import { getSafeFrom } from '~/test/utils/safeHelper'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { safeTransactionsSelector } from '~/routes/safe/store/selectors'
|
import { safeTransactionsSelector } from '~/routes/safe/store/selectors'
|
||||||
import { testTransactionFrom, testSizeOfTransactions } from './utils/historyServiceHelper'
|
import { testTransactionFrom, testSizeOfTransactions } from './utils/historyServiceHelper'
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,15 @@ import { SAFELIST_ADDRESS } from '~/routes/routes'
|
||||||
import SafeView from '~/routes/safe/component/Safe'
|
import SafeView from '~/routes/safe/component/Safe'
|
||||||
import AppRoutes from '~/routes'
|
import AppRoutes from '~/routes'
|
||||||
import { WITHDRAW_BUTTON_TEXT } from '~/routes/safe/component/Safe/DailyLimit'
|
import { WITHDRAW_BUTTON_TEXT } from '~/routes/safe/component/Safe/DailyLimit'
|
||||||
import { getBalanceInEtherOf } from '~/wallets/getWeb3'
|
import { getBalanceInEtherOf } from '~/logic/wallets/getWeb3'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
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 { WITHDRAW_INDEX } from '~/test/builder/safe.dom.utils'
|
import { WITHDRAW_INDEX } from '~/test/builder/safe.dom.utils'
|
||||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
import { getSafeFrom } from '~/test/utils/safeHelper'
|
import { getSafeFrom } from '~/test/utils/safeHelper'
|
||||||
import { filterMoveButtonsFrom } from '~/test/builder/safe.dom.builder'
|
import { filterMoveButtonsFrom } from '~/test/builder/safe.dom.builder'
|
||||||
import { fetchTokens } from '~/routes/tokens/store/actions/fetchTokens'
|
import { fetchTokens } from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
|
import { getDailyLimitFrom } from '~/logic/contracts/dailyLimitContracts'
|
||||||
|
|
||||||
describe('React DOM TESTS > Withdraw funds from safe', () => {
|
describe('React DOM TESTS > Withdraw funds from safe', () => {
|
||||||
let store
|
let store
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as TestUtils from 'react-dom/test-utils'
|
import * as TestUtils from 'react-dom/test-utils'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type Match } from 'react-router-dom'
|
import { type Match } from 'react-router-dom'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import TokenComponent from '~/routes/tokens/component/Token'
|
import TokenComponent from '~/routes/tokens/component/Token'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as TestUtils from 'react-dom/test-utils'
|
import * as TestUtils from 'react-dom/test-utils'
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type Match } from 'react-router-dom'
|
import { type Match } from 'react-router-dom'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import TokenComponent from '~/routes/tokens/component/Token'
|
import TokenComponent from '~/routes/tokens/component/Token'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as TestUtils from 'react-dom/test-utils'
|
import * as TestUtils from 'react-dom/test-utils'
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
|
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
|
||||||
import { aNewStore } from '~/store'
|
import { aNewStore } from '~/store'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type Match } from 'react-router-dom'
|
import { type Match } from 'react-router-dom'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
|
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type Match } from 'react-router-dom'
|
import { type Match } from 'react-router-dom'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
|
import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import abi from 'ethereumjs-abi'
|
import abi from 'ethereumjs-abi'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { getGnosisSafeInstanceAt } from '~/wallets/safeContracts'
|
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
import GnoStepper from '~/components/Stepper'
|
import GnoStepper from '~/components/Stepper'
|
||||||
import Stepper from '@material-ui/core/Stepper'
|
import Stepper from '@material-ui/core/Stepper'
|
||||||
import TestUtils from 'react-dom/test-utils'
|
import TestUtils from 'react-dom/test-utils'
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
import contract from 'truffle-contract'
|
import contract from 'truffle-contract'
|
||||||
import { getProviderInfo, getBalanceInEtherOf, getWeb3 } from '~/wallets/getWeb3'
|
import { getProviderInfo, getBalanceInEtherOf, getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { promisify } from '~/utils/promisify'
|
import { promisify } from '~/utils/promisify'
|
||||||
import withdraw, { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/withdraw'
|
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import Token from '#/test/TestToken.json'
|
import Token from '#/test/TestToken.json'
|
||||||
import { ensureOnce } from '~/utils/singleton'
|
import { ensureOnce } from '~/utils/singleton'
|
||||||
import { toNative } from '~/wallets/tokens'
|
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/WithdrawForm'
|
||||||
|
import { withdraw } from '~/logic/safe/safeFrontendOperations'
|
||||||
|
import { toNative } from '~/logic/wallets/tokens'
|
||||||
|
|
||||||
export const addEtherTo = async (address: string, eth: string) => {
|
export const addEtherTo = async (address: string, eth: string) => {
|
||||||
const web3 = getWeb3()
|
const web3 = getWeb3()
|
||||||
|
|
|
@ -2,7 +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 { checkMinedTx } from '~/test/builder/safe.dom.utils'
|
import { checkMinedTx } from '~/test/builder/safe.dom.utils'
|
||||||
import { getGnosisSafeInstanceAt } from '~/wallets/safeContracts'
|
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
import Threshold from '~/routes/safe/component/Threshold'
|
import Threshold from '~/routes/safe/component/Threshold'
|
||||||
import { whenExecuted } from '~/test/utils/logTransactions'
|
import { whenExecuted } from '~/test/utils/logTransactions'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import logo from '~/assets/icons/icon_etherTokens.svg'
|
import logo from '~/assets/icons/icon_etherTokens.svg'
|
||||||
import { getBalanceInEtherOf } from '~/wallets/getWeb3'
|
import { getBalanceInEtherOf } from '~/logic/wallets/getWeb3'
|
||||||
import { makeToken, type Token } from '~/routes/tokens/store/model/token'
|
import { makeToken, type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
export const ETH_ADDRESS = '0'
|
export const ETH_ADDRESS = '0'
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { getGnosisSafeContract } from '~/wallets/safeContracts'
|
|
||||||
import { getWeb3 } from '~/wallets/getWeb3'
|
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
|
||||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
|
||||||
import { executeTransaction, approveTransaction } from '~/wallets/safeOperations'
|
|
||||||
|
|
||||||
export const TX_NAME_PARAM = 'txName'
|
|
||||||
export const TX_DESTINATION_PARAM = 'txDestination'
|
|
||||||
export const TX_VALUE_PARAM = 'txValue'
|
|
||||||
|
|
||||||
export const EXECUTED_CONFIRMATION_HASH = 'EXECUTED'
|
|
||||||
|
|
||||||
const hasOneOwner = (safe: Safe) => {
|
|
||||||
const owners = safe.get('owners')
|
|
||||||
if (!owners) {
|
|
||||||
throw new Error('Received a Safe without owners when creating a tx')
|
|
||||||
}
|
|
||||||
|
|
||||||
return owners.count() === 1
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getSafeEthereumInstance = async (safeAddress: string) => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const GnosisSafe = await getGnosisSafeContract(web3)
|
|
||||||
return GnosisSafe.at(safeAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createTransaction = async (
|
|
||||||
safe: Safe,
|
|
||||||
name: string,
|
|
||||||
to: string,
|
|
||||||
value: number,
|
|
||||||
nonce: number,
|
|
||||||
sender: string,
|
|
||||||
data: string = EMPTY_DATA,
|
|
||||||
) => {
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const safeAddress = safe.get('address')
|
|
||||||
const threshold = safe.get('threshold')
|
|
||||||
const valueInWei = web3.toWei(value, 'ether')
|
|
||||||
const CALL = 0
|
|
||||||
|
|
||||||
const isExecution = hasOneOwner(safe) || threshold === 1
|
|
||||||
|
|
||||||
return isExecution
|
|
||||||
? executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
|
|
||||||
: approveTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
|
|
||||||
}
|
|
Loading…
Reference in New Issue