Merge branch 'development' into issue-1144
This commit is contained in:
commit
b119f3e88f
|
@ -85,6 +85,10 @@ const isSafeMethod = (methodId: string): boolean => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const decodeMethods = (data: string): DataDecoded | null => {
|
export const decodeMethods = (data: string): DataDecoded | null => {
|
||||||
|
if(!data.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const [methodId, params] = [data.slice(0, 10), data.slice(10)]
|
const [methodId, params] = [data.slice(0, 10), data.slice(10)]
|
||||||
|
|
||||||
if (isSafeMethod(methodId)) {
|
if (isSafeMethod(methodId)) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import createDecorator from 'final-form-calculate'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useField, useFormState } from 'react-final-form'
|
import { useField, useFormState } from 'react-final-form'
|
||||||
|
|
||||||
import { SafeApp } from 'src/routes/safe/components/Apps/types'
|
import { SafeApp } from 'src/routes/safe/components/Apps/types.d'
|
||||||
import { getAppInfoFromUrl, getIpfsLinkFromEns, uniqueApp } from 'src/routes/safe/components/Apps/utils'
|
import { getAppInfoFromUrl, getIpfsLinkFromEns, uniqueApp } from 'src/routes/safe/components/Apps/utils'
|
||||||
import { composeValidators, required } from 'src/components/forms/validator'
|
import { composeValidators, required } from 'src/components/forms/validator'
|
||||||
import Field from 'src/components/forms/Field'
|
import Field from 'src/components/forms/Field'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useFormState } from 'react-final-form'
|
import { useFormState } from 'react-final-form'
|
||||||
|
|
||||||
import { SafeApp } from 'src/routes/safe/components/Apps/types'
|
import { SafeApp } from 'src/routes/safe/components/Apps/types.d'
|
||||||
import { isAppManifestValid } from 'src/routes/safe/components/Apps/utils'
|
import { isAppManifestValid } from 'src/routes/safe/components/Apps/utils'
|
||||||
|
|
||||||
interface SubmitButtonStatusProps {
|
interface SubmitButtonStatusProps {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import AppAgreement from './AppAgreement'
|
||||||
import AppUrl, { AppInfoUpdater, appUrlResolver } from './AppUrl'
|
import AppUrl, { AppInfoUpdater, appUrlResolver } from './AppUrl'
|
||||||
import SubmitButtonStatus from './SubmitButtonStatus'
|
import SubmitButtonStatus from './SubmitButtonStatus'
|
||||||
|
|
||||||
import { SafeApp } from 'src/routes/safe/components/Apps/types'
|
import { SafeApp } from 'src/routes/safe/components/Apps/types.d'
|
||||||
import GnoForm from 'src/components/forms/GnoForm'
|
import GnoForm from 'src/components/forms/GnoForm'
|
||||||
import Img from 'src/components/layout/Img'
|
import Img from 'src/components/layout/Img'
|
||||||
import appsIconSvg from 'src/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
import appsIconSvg from 'src/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { List } from 'immutable'
|
||||||
import { FIXED } from 'src/components/Table/sorting'
|
import { FIXED } from 'src/components/Table/sorting'
|
||||||
import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount'
|
import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount'
|
||||||
import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers'
|
import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers'
|
||||||
import { TableColumn } from 'src/components/Table/types'
|
import { TableColumn } from 'src/components/Table/types.d'
|
||||||
import { AVAILABLE_CURRENCIES, BalanceCurrencyList } from 'src/logic/currencyValues/store/model/currencyValues'
|
import { AVAILABLE_CURRENCIES, BalanceCurrencyList } from 'src/logic/currencyValues/store/model/currencyValues'
|
||||||
import { Token } from 'src/logic/tokens/store/model/token'
|
import { Token } from 'src/logic/tokens/store/model/token'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { TableColumn } from 'src/components/Table/types'
|
import { TableColumn } from 'src/components/Table/types.d'
|
||||||
import { ModulePair } from 'src/routes/safe/store/models/safe'
|
import { ModulePair } from 'src/routes/safe/store/models/safe'
|
||||||
|
|
||||||
export const MODULES_TABLE_ADDRESS_ID = 'address'
|
export const MODULES_TABLE_ADDRESS_ID = 'address'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { TableColumn } from 'src/components/Table/types'
|
import { TableColumn } from 'src/components/Table/types.d'
|
||||||
|
|
||||||
export const OWNERS_TABLE_NAME_ID = 'name'
|
export const OWNERS_TABLE_NAME_ID = 'name'
|
||||||
export const OWNERS_TABLE_ADDRESS_ID = 'address'
|
export const OWNERS_TABLE_ADDRESS_ID = 'address'
|
||||||
|
|
|
@ -22,9 +22,12 @@ import Paragraph from 'src/components/layout/Paragraph'
|
||||||
import LinkWithRef from 'src/components/layout/Link'
|
import LinkWithRef from 'src/components/layout/Link'
|
||||||
import { shortVersionOf } from 'src/logic/wallets/ethAddresses'
|
import { shortVersionOf } from 'src/logic/wallets/ethAddresses'
|
||||||
import { Transaction } from 'src/routes/safe/store/models/types/transaction'
|
import { Transaction } from 'src/routes/safe/store/models/types/transaction'
|
||||||
|
import { DataDecoded } from 'src/routes/safe/store/models/types/transactions.d'
|
||||||
|
import DividerLine from 'src/components/DividerLine'
|
||||||
|
|
||||||
export const TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID = 'tx-description-custom-value'
|
export const TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID = 'tx-description-custom-value'
|
||||||
export const TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID = 'tx-description-custom-data'
|
export const TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID = 'tx-description-custom-data'
|
||||||
|
export const TRANSACTION_DESC_ACTION_TEST_ID = 'tx-description-action-data'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
@ -45,42 +48,55 @@ const TxInfo = styled.div`
|
||||||
padding: 8px 8px 8px 16px;
|
padding: 8px 8px 8px 16px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const MultiSendCustomData = ({ tx, order }: { tx: MultiSendDetails; order: number }): React.ReactElement => {
|
const TxInfoDetails = ({ data }: { data: DataDecoded }): React.ReactElement => (
|
||||||
|
<TxInfo>
|
||||||
|
<TxDetailsMethodName size="lg" strong>
|
||||||
|
{data.method}
|
||||||
|
</TxDetailsMethodName>
|
||||||
|
|
||||||
|
{data.parameters.map((param, index) => (
|
||||||
|
<TxDetailsMethodParam key={`${data.method}_param-${index}`}>
|
||||||
|
<InlineText size="lg" strong>
|
||||||
|
{param.name}({param.type}):
|
||||||
|
</InlineText>
|
||||||
|
|
||||||
|
<Value method={data.method} type={param.type} value={param.value} />
|
||||||
|
</TxDetailsMethodParam>
|
||||||
|
))}
|
||||||
|
</TxInfo>
|
||||||
|
)
|
||||||
|
|
||||||
|
const MultiSendCustomDataAction = ({ tx, order }: { tx: MultiSendDetails; order: number }): React.ReactElement => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const methodName = tx.data?.method ? ` (${tx.data.method})` : ''
|
const methodName = tx.data?.method ? ` (${tx.data.method})` : ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Collapse
|
||||||
<Collapse
|
collapseClassName={classes.collapse}
|
||||||
collapseClassName={classes.collapse}
|
headerWrapperClassName={classes.collapseHeaderWrapper}
|
||||||
headerWrapperClassName={classes.collapseHeaderWrapper}
|
title={<IconText iconSize="sm" iconType="code" text={`Action ${order + 1}${methodName}`} textSize="lg" />}
|
||||||
title={<IconText iconSize="sm" iconType="code" text={`Action ${order + 1}${methodName}`} textSize="lg" />}
|
>
|
||||||
>
|
<TxDetailsContent>
|
||||||
<TxDetailsContent>
|
<TxInfo>
|
||||||
<TxInfo>
|
<Bold>Send {humanReadableValue(tx.value)} ETH to:</Bold>
|
||||||
<Bold>Send {humanReadableValue(tx.value)} ETH to:</Bold>
|
<OwnerAddressTableCell address={tx.to} showLinks />
|
||||||
<OwnerAddressTableCell address={tx.to} showLinks />
|
</TxInfo>
|
||||||
</TxInfo>
|
|
||||||
{tx.data && (
|
{!!tx.data && <TxInfoDetails data={tx.data} />}
|
||||||
<TxInfo>
|
</TxDetailsContent>
|
||||||
<TxDetailsMethodName size="lg">
|
</Collapse>
|
||||||
<strong>{tx.data.method}</strong>
|
)
|
||||||
</TxDetailsMethodName>
|
}
|
||||||
{tx.data?.parameters.map((param, index) => (
|
|
||||||
<TxDetailsMethodParam key={`${tx.operation}_${tx.to}_${tx.data.method}_param-${index}`}>
|
const MultiSendCustomData = ({ txDetails }: { txDetails: MultiSendDetails[] }): React.ReactElement => {
|
||||||
<InlineText size="lg">
|
const classes = useStyles()
|
||||||
<strong>
|
|
||||||
{param.name}({param.type}):
|
return (
|
||||||
</strong>
|
<Block className={classes.multiSendTxData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
|
||||||
</InlineText>
|
{txDetails.map((tx, index) => (
|
||||||
<Value method={methodName} type={param.type} value={param.value} />
|
<MultiSendCustomDataAction key={`${tx.to}-row-${index}`} tx={tx} order={index} />
|
||||||
</TxDetailsMethodParam>
|
))}
|
||||||
))}
|
</Block>
|
||||||
</TxInfo>
|
|
||||||
)}
|
|
||||||
</TxDetailsContent>
|
|
||||||
</Collapse>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,13 +144,31 @@ const TxData = ({ data }: { data: string }): React.ReactElement => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TxActionData = ({ dataDecoded }: { dataDecoded: DataDecoded }): React.ReactElement => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DividerLine withArrow={false} />
|
||||||
|
|
||||||
|
<Block className={classes.txData} data-testid={TRANSACTION_DESC_ACTION_TEST_ID}>
|
||||||
|
<Bold>Action</Bold>
|
||||||
|
<TxInfoDetails data={dataDecoded} />
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<DividerLine withArrow={false} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
interface GenericCustomDataProps {
|
interface GenericCustomDataProps {
|
||||||
amount?: string
|
amount?: string
|
||||||
data: string
|
data: string
|
||||||
recipient: string
|
recipient: string
|
||||||
|
storedTx: Transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
const GenericCustomData = ({ amount = '0', data, recipient }: GenericCustomDataProps): React.ReactElement => {
|
const GenericCustomData = ({ amount = '0', data, recipient, storedTx }: GenericCustomDataProps): React.ReactElement => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const recipientName = useSelector((state) => getNameFromAddressBook(state, recipient))
|
const recipientName = useSelector((state) => getNameFromAddressBook(state, recipient))
|
||||||
|
|
||||||
|
@ -148,6 +182,9 @@ const GenericCustomData = ({ amount = '0', data, recipient }: GenericCustomDataP
|
||||||
<EtherscanLink knownAddress={false} type="address" value={recipient} />
|
<EtherscanLink knownAddress={false} type="address" value={recipient} />
|
||||||
)}
|
)}
|
||||||
</Block>
|
</Block>
|
||||||
|
|
||||||
|
{!!storedTx?.dataDecoded && <TxActionData dataDecoded={storedTx.dataDecoded} />}
|
||||||
|
|
||||||
<Block className={classes.txData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
|
<Block className={classes.txData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
|
||||||
<Bold>Data (hex encoded):</Bold>
|
<Bold>Data (hex encoded):</Bold>
|
||||||
<TxData data={data} />
|
<TxData data={data} />
|
||||||
|
@ -164,16 +201,12 @@ interface CustomDescriptionProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomDescription = ({ amount, data, recipient, storedTx }: CustomDescriptionProps): React.ReactElement => {
|
const CustomDescription = ({ amount, data, recipient, storedTx }: CustomDescriptionProps): React.ReactElement => {
|
||||||
const classes = useStyles()
|
const txDetails = (storedTx.multiSendTx && extractMultiSendDecodedData(storedTx).txDetails) ?? undefined
|
||||||
|
|
||||||
return storedTx.multiSendTx ? (
|
return txDetails ? (
|
||||||
<Block className={classes.multiSendTxData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
|
<MultiSendCustomData txDetails={txDetails} />
|
||||||
{extractMultiSendDecodedData(storedTx).txDetails?.map((tx, index) => (
|
|
||||||
<MultiSendCustomData key={`${tx.to}-row-${index}`} tx={tx} order={index} />
|
|
||||||
))}
|
|
||||||
</Block>
|
|
||||||
) : (
|
) : (
|
||||||
<GenericCustomData amount={amount} data={data} recipient={recipient} />
|
<GenericCustomData amount={amount} data={data} recipient={recipient} storedTx={storedTx} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import SettingsTxIcon from './assets/settings.svg'
|
||||||
|
|
||||||
import CustomIconText from 'src/components/CustomIconText'
|
import CustomIconText from 'src/components/CustomIconText'
|
||||||
import { getAppInfoFromOrigin, getAppInfoFromUrl } from 'src/routes/safe/components/Apps/utils'
|
import { getAppInfoFromOrigin, getAppInfoFromUrl } from 'src/routes/safe/components/Apps/utils'
|
||||||
import { SafeApp } from 'src/routes/safe/components/Apps/types'
|
import { SafeApp } from 'src/routes/safe/components/Apps/types.d'
|
||||||
|
|
||||||
const typeToIcon = {
|
const typeToIcon = {
|
||||||
outgoing: OutgoingTxIcon,
|
outgoing: OutgoingTxIcon,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import React from 'react'
|
||||||
import TxType from './TxType'
|
import TxType from './TxType'
|
||||||
|
|
||||||
import { buildOrderFieldFrom } from 'src/components/Table/sorting'
|
import { buildOrderFieldFrom } from 'src/components/Table/sorting'
|
||||||
import { TableColumn } from 'src/components/Table/types'
|
import { TableColumn } from 'src/components/Table/types.d'
|
||||||
import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
|
import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
|
||||||
import { INCOMING_TX_TYPES } from 'src/routes/safe/store/models/incomingTransaction'
|
import { INCOMING_TX_TYPES } from 'src/routes/safe/store/models/incomingTransaction'
|
||||||
import { Transaction } from 'src/routes/safe/store/models/types/transaction'
|
import { Transaction } from 'src/routes/safe/store/models/types/transaction'
|
||||||
|
|
|
@ -13,8 +13,7 @@ describe('TxsTable Columns > getTxTableData', () => {
|
||||||
const txRow = txTableData.first()
|
const txRow = txTableData.first()
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
// expect(txRow[TX_TABLE_RAW_CANCEL_TX_ID]).toEqual(mockedCancelTransaction)
|
expect(txRow[TX_TABLE_RAW_CANCEL_TX_ID]).toEqual(mockedCancelTransaction)
|
||||||
expect(txRow[TX_TABLE_RAW_CANCEL_TX_ID]).toBeUndefined()
|
|
||||||
})
|
})
|
||||||
it('should not include CancelTx object inside TxTableData', () => {
|
it('should not include CancelTx object inside TxTableData', () => {
|
||||||
// Given
|
// Given
|
||||||
|
|
|
@ -8,7 +8,7 @@ import activateAssetsByBalance from 'src/logic/tokens/store/actions/activateAsse
|
||||||
import fetchSafeTokens from 'src/logic/tokens/store/actions/fetchSafeTokens'
|
import fetchSafeTokens from 'src/logic/tokens/store/actions/fetchSafeTokens'
|
||||||
import { fetchTokens } from 'src/logic/tokens/store/actions/fetchTokens'
|
import { fetchTokens } from 'src/logic/tokens/store/actions/fetchTokens'
|
||||||
import { COINS_LOCATION_REGEX, COLLECTIBLES_LOCATION_REGEX } from 'src/routes/safe/components/Balances'
|
import { COINS_LOCATION_REGEX, COLLECTIBLES_LOCATION_REGEX } from 'src/routes/safe/components/Balances'
|
||||||
import { Dispatch } from 'src/routes/safe/store/actions/types'
|
import { Dispatch } from 'src/routes/safe/store/actions/types.d'
|
||||||
|
|
||||||
export const useFetchTokens = (safeAddress: string): void => {
|
export const useFetchTokens = (safeAddress: string): void => {
|
||||||
const dispatch = useDispatch<Dispatch>()
|
const dispatch = useDispatch<Dispatch>()
|
||||||
|
|
|
@ -8,7 +8,7 @@ import fetchLatestMasterContractVersion from 'src/routes/safe/store/actions/fetc
|
||||||
import fetchSafe from 'src/routes/safe/store/actions/fetchSafe'
|
import fetchSafe from 'src/routes/safe/store/actions/fetchSafe'
|
||||||
import fetchTransactions from 'src/routes/safe/store/actions/transactions/fetchTransactions'
|
import fetchTransactions from 'src/routes/safe/store/actions/transactions/fetchTransactions'
|
||||||
import fetchSafeCreationTx from 'src/routes/safe/store/actions/fetchSafeCreationTx'
|
import fetchSafeCreationTx from 'src/routes/safe/store/actions/fetchSafeCreationTx'
|
||||||
import { Dispatch } from 'src/routes/safe/store/actions/types'
|
import { Dispatch } from 'src/routes/safe/store/actions/types.d'
|
||||||
|
|
||||||
export const useLoadSafe = (safeAddress: string): void => {
|
export const useLoadSafe = (safeAddress: string): void => {
|
||||||
const dispatch = useDispatch<Dispatch>()
|
const dispatch = useDispatch<Dispatch>()
|
||||||
|
|
|
@ -1,59 +1,54 @@
|
||||||
import { getNewTxNonce, shouldExecuteTransaction } from 'src/routes/safe/store/actions/utils'
|
import { getNewTxNonce, shouldExecuteTransaction } from 'src/routes/safe/store/actions/utils'
|
||||||
|
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
|
||||||
|
import { TxServiceModel } from 'src/routes/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions'
|
||||||
|
|
||||||
describe('Store actions utils > getNewTxNonce', () => {
|
describe('Store actions utils > getNewTxNonce', () => {
|
||||||
it(`should return txNonce if it's a valid value`, async () => {
|
it(`Should return passed predicted transaction nonce if it's a valid value`, async () => {
|
||||||
// Given
|
// Given
|
||||||
const txNonce = '45'
|
const txNonce = '45'
|
||||||
const lastTx = {
|
const lastTx = { nonce: 44 } as TxServiceModel
|
||||||
nonce: 44,
|
const safeInstance = {}
|
||||||
}
|
|
||||||
const safeInstance = {
|
|
||||||
nonce: () =>
|
|
||||||
Promise.resolve({
|
|
||||||
toString: () => Promise.resolve('45'),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance)
|
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance as GnosisSafe)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(nonce).toBe('45')
|
expect(nonce).toBe('45')
|
||||||
})
|
})
|
||||||
|
|
||||||
it(`should return lastTx.nonce + 1 if txNonce is not valid`, async () => {
|
it(`Should return nonce of a last transaction + 1 if passed nonce is less than last transaction or invalid`, async () => {
|
||||||
// Given
|
// Given
|
||||||
const txNonce = ''
|
const txNonce = ''
|
||||||
const lastTx = {
|
const lastTx = { nonce: 44 } as TxServiceModel
|
||||||
nonce: 44,
|
|
||||||
}
|
|
||||||
const safeInstance = {
|
const safeInstance = {
|
||||||
nonce: () =>
|
methods: {
|
||||||
Promise.resolve({
|
nonce: () => ({
|
||||||
toString: () => Promise.resolve('45'),
|
call: () => Promise.resolve('45'),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// When
|
// When
|
||||||
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance)
|
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance as GnosisSafe)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(nonce).toBe('45')
|
expect(nonce).toBe('45')
|
||||||
})
|
})
|
||||||
|
|
||||||
it(`should retrieve contract's instance nonce value, if txNonce and lastTx are not valid`, async () => {
|
it(`Should retrieve contract's instance nonce value as a fallback, if txNonce and lastTx are not valid`, async () => {
|
||||||
// Given
|
// Given
|
||||||
const txNonce = ''
|
const txNonce = ''
|
||||||
const lastTx = null
|
const lastTx = null
|
||||||
const safeInstance = {
|
const safeInstance = {
|
||||||
nonce: () =>
|
methods: {
|
||||||
Promise.resolve({
|
nonce: () => ({
|
||||||
toString: () => Promise.resolve('45'),
|
call: () => Promise.resolve('45'),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// When
|
// When
|
||||||
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance)
|
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance as GnosisSafe)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(nonce).toBe('45')
|
expect(nonce).toBe('45')
|
||||||
|
@ -64,18 +59,17 @@ describe('Store actions utils > shouldExecuteTransaction', () => {
|
||||||
it(`should return false if there's a previous tx pending to be executed`, async () => {
|
it(`should return false if there's a previous tx pending to be executed`, async () => {
|
||||||
// Given
|
// Given
|
||||||
const safeInstance = {
|
const safeInstance = {
|
||||||
getThreshold: () =>
|
methods: {
|
||||||
Promise.resolve({
|
getThreshold: () => ({
|
||||||
toNumber: () => 1,
|
call: () => Promise.resolve('1'),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const nonce = '1'
|
const nonce = '1'
|
||||||
const lastTx = {
|
const lastTx = { isExecuted: false } as TxServiceModel
|
||||||
isExecuted: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
const isExecution = await shouldExecuteTransaction(safeInstance, nonce, lastTx)
|
const isExecution = await shouldExecuteTransaction(safeInstance as GnosisSafe, nonce, lastTx)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(isExecution).toBeFalsy()
|
expect(isExecution).toBeFalsy()
|
||||||
|
@ -84,18 +78,17 @@ describe('Store actions utils > shouldExecuteTransaction', () => {
|
||||||
it(`should return false if threshold is greater than 1`, async () => {
|
it(`should return false if threshold is greater than 1`, async () => {
|
||||||
// Given
|
// Given
|
||||||
const safeInstance = {
|
const safeInstance = {
|
||||||
getThreshold: () =>
|
methods: {
|
||||||
Promise.resolve({
|
getThreshold: () => ({
|
||||||
toNumber: () => 2,
|
call: () => Promise.resolve('2'),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const nonce = '1'
|
const nonce = '1'
|
||||||
const lastTx = {
|
const lastTx = { isExecuted: true } as TxServiceModel
|
||||||
isExecuted: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
const isExecution = await shouldExecuteTransaction(safeInstance, nonce, lastTx)
|
const isExecution = await shouldExecuteTransaction(safeInstance as GnosisSafe, nonce, lastTx)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(isExecution).toBeFalsy()
|
expect(isExecution).toBeFalsy()
|
||||||
|
@ -104,18 +97,17 @@ describe('Store actions utils > shouldExecuteTransaction', () => {
|
||||||
it(`should return true is threshold is 1 and previous tx is executed`, async () => {
|
it(`should return true is threshold is 1 and previous tx is executed`, async () => {
|
||||||
// Given
|
// Given
|
||||||
const safeInstance = {
|
const safeInstance = {
|
||||||
getThreshold: () =>
|
methods: {
|
||||||
Promise.resolve({
|
getThreshold: () => ({
|
||||||
toNumber: () => 1,
|
call: () => Promise.resolve('1'),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const nonce = '1'
|
const nonce = '1'
|
||||||
const lastTx = {
|
const lastTx = { isExecuted: true } as TxServiceModel
|
||||||
isExecuted: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
const isExecution = await shouldExecuteTransaction(safeInstance, nonce, lastTx)
|
const isExecution = await shouldExecuteTransaction(safeInstance as GnosisSafe, nonce, lastTx)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(isExecution).toBeTruthy()
|
expect(isExecution).toBeTruthy()
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { List, Map } from 'immutable'
|
import { List, Map } from 'immutable'
|
||||||
|
|
||||||
import { decodeMethods } from 'src/logic/contracts/methodIds'
|
|
||||||
import { TOKEN_REDUCER_ID } from 'src/logic/tokens/store/reducer/tokens'
|
import { TOKEN_REDUCER_ID } from 'src/logic/tokens/store/reducer/tokens'
|
||||||
import {
|
import {
|
||||||
getERC20DecimalsAndSymbol,
|
getERC20DecimalsAndSymbol,
|
||||||
|
@ -318,30 +317,6 @@ export type TxToMock = TxArgs & {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mockTransaction = (tx: TxToMock, safeAddress: string, state: AppReduxState): Promise<Transaction> => {
|
export const mockTransaction = (tx: TxToMock, safeAddress: string, state: AppReduxState): Promise<Transaction> => {
|
||||||
const submissionDate = new Date().toISOString()
|
|
||||||
|
|
||||||
const transactionStructure: TxServiceModel = {
|
|
||||||
blockNumber: null,
|
|
||||||
confirmationsRequired: null,
|
|
||||||
dataDecoded: decodeMethods(tx.data),
|
|
||||||
ethGasPrice: null,
|
|
||||||
executionDate: null,
|
|
||||||
executor: null,
|
|
||||||
fee: null,
|
|
||||||
gasUsed: null,
|
|
||||||
isExecuted: false,
|
|
||||||
isSuccessful: null,
|
|
||||||
modified: submissionDate,
|
|
||||||
origin: null,
|
|
||||||
safe: safeAddress,
|
|
||||||
safeTxHash: null,
|
|
||||||
signatures: null,
|
|
||||||
submissionDate,
|
|
||||||
transactionHash: null,
|
|
||||||
confirmations: [],
|
|
||||||
...tx,
|
|
||||||
}
|
|
||||||
|
|
||||||
const knownTokens: Map<string, Token> = state[TOKEN_REDUCER_ID]
|
const knownTokens: Map<string, Token> = state[TOKEN_REDUCER_ID]
|
||||||
const safe: SafeRecord = state[SAFE_REDUCER_ID].getIn(['safes', safeAddress])
|
const safe: SafeRecord = state[SAFE_REDUCER_ID].getIn(['safes', safeAddress])
|
||||||
const cancellationTxs = state[CANCELLATION_TRANSACTIONS_REDUCER_ID].get(safeAddress) || Map()
|
const cancellationTxs = state[CANCELLATION_TRANSACTIONS_REDUCER_ID].get(safeAddress) || Map()
|
||||||
|
@ -353,7 +328,7 @@ export const mockTransaction = (tx: TxToMock, safeAddress: string, state: AppRed
|
||||||
knownTokens,
|
knownTokens,
|
||||||
outgoingTxs,
|
outgoingTxs,
|
||||||
safe,
|
safe,
|
||||||
tx: transactionStructure,
|
tx: (tx as unknown) as TxServiceModel,
|
||||||
txCode: EMPTY_DATA,
|
txCode: EMPTY_DATA,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,4 +143,4 @@ export default handleActions(
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
export * from './types/safe.d'
|
export * from './types/safe'
|
||||||
|
|
|
@ -11,11 +11,13 @@ export interface SafeReducerState {
|
||||||
latestMasterContractVersion: string
|
latestMasterContractVersion: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SafeReducerStateSerialized extends SafeReducerState {
|
interface SafeReducerStateJSON {
|
||||||
|
defaultSafe: 'NOT_ASKED' | string | undefined
|
||||||
safes: Record<string, SafeRecordProps>
|
safes: Record<string, SafeRecordProps>
|
||||||
|
latestMasterContractVersion: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SafeReducerMap extends Map<string, any> {
|
export interface SafeReducerMap extends Map<string, any> {
|
||||||
toJS(): SafeReducerStateSerialized
|
toJS(): SafeReducerStateJSON
|
||||||
get<K extends keyof SafeReducerState>(key: K): SafeReducerState[K]
|
get<K extends keyof SafeReducerState>(key: K): SafeReducerState[K]
|
||||||
}
|
}
|
Loading…
Reference in New Issue