Skip to content

Commit

Permalink
Refactor: move DecodedTx logic to a hook; extract Approval editor
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh committed Jul 13, 2023
1 parent 60ec5ef commit 3edb2c9
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 155 deletions.
14 changes: 9 additions & 5 deletions src/components/common/BatchSidebar/BatchTxItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import css from './styles.module.css'

type BatchTxItemProps = DraftBatchItem & {
count: number
onDelete: () => void
onDelete?: () => void
}

const BatchTxItem = ({ count, timestamp, txDetails, onDelete }: BatchTxItemProps) => {
Expand Down Expand Up @@ -39,11 +39,15 @@ const BatchTxItem = ({ count, timestamp, txDetails, onDelete }: BatchTxItemProps

<DateTime value={timestamp} />

<Box className={css.separator} />
{onDelete && (
<>
<Box className={css.separator} />

<ButtonBase onClick={onDelete}>
<SvgIcon component={DeleteIcon} inheritViewBox fontSize="small" />
</ButtonBase>
<ButtonBase onClick={onDelete}>
<SvgIcon component={DeleteIcon} inheritViewBox fontSize="small" />
</ButtonBase>
</>
)}
</Box>
</Box>
)
Expand Down
13 changes: 1 addition & 12 deletions src/components/common/BatchSidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { SyntheticEvent } from 'react'
import type { TransactionDetails } from '@safe-global/safe-gateway-typescript-sdk'
import { type MetaTransactionData, OperationType } from '@safe-global/safe-core-sdk-types'
import { useCallback, useContext } from 'react'
import { Button, Divider, Drawer, SvgIcon, Typography } from '@mui/material'
import { useDraftBatch, useUpdateBatch } from '@/hooks/useDraftBatch'
Expand All @@ -11,15 +9,6 @@ import BatchTxItem from './BatchTxItem'
import ConfirmBatchFlow from '@/components/tx-flow/flows/ConfirmBatch'
import PlusIcon from '@/public/images/common/plus.svg'

const getData = (txDetails: TransactionDetails): MetaTransactionData => {
return {
to: txDetails.txData?.to.value ?? '',
value: txDetails.txData?.value ?? '0',
data: txDetails.txData?.hexData ?? '0x',
operation: OperationType.Call, // only calls can be batched
}
}

const BatchSidebar = ({ isOpen, onToggle }: { isOpen: boolean; onToggle: (open: boolean) => void }) => {
const { setTxFlow } = useContext(TxModalContext)
const batchTxs = useDraftBatch()
Expand All @@ -44,7 +33,7 @@ const BatchSidebar = ({ isOpen, onToggle }: { isOpen: boolean; onToggle: (open:
e.preventDefault()
if (!batchTxs.length) return
closeSidebar()
setTxFlow(<ConfirmBatchFlow calls={batchTxs.map((item) => getData(item.txDetails))} onSubmit={clearBatch} />)
setTxFlow(<ConfirmBatchFlow onSubmit={clearBatch} />, undefined, false)
},
[setTxFlow, batchTxs, closeSidebar, clearBatch],
)
Expand Down
33 changes: 28 additions & 5 deletions src/components/tx-flow/flows/ConfirmBatch/index.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,56 @@
import { type ReactElement, useContext, useEffect } from 'react'
import { type TransactionDetails } from '@safe-global/safe-gateway-typescript-sdk'
import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm'
import { createMultiSendCallOnlyTx } from '@/services/tx/tx-sender'
import { SafeTxContext } from '../../SafeTxProvider'
import type { MetaTransactionData } from '@safe-global/safe-core-sdk-types'
import { OperationType } from '@safe-global/safe-core-sdk-types'
import TxLayout from '../../common/TxLayout'
import BatchIcon from '@/public/images/common/batch.svg'
import { useDraftBatch } from '@/hooks/useDraftBatch'
import BatchTxItem from '@/components/common/BatchSidebar/BatchTxItem'

type ConfirmBatchProps = {
calls: MetaTransactionData[]
onSubmit: () => void
}

const ConfirmBatch = ({ calls, onSubmit }: ConfirmBatchProps): ReactElement => {
const getData = (txDetails: TransactionDetails): MetaTransactionData => {
return {
to: txDetails.txData?.to.value ?? '',
value: txDetails.txData?.value ?? '0',
data: txDetails.txData?.hexData ?? '0x',
operation: OperationType.Call, // only calls can be batched
}
}

const ConfirmBatch = ({ onSubmit }: ConfirmBatchProps): ReactElement => {
const { setSafeTx, setSafeTxError } = useContext(SafeTxContext)
const batchTxs = useDraftBatch()

useEffect(() => {
const calls = batchTxs.map((tx) => getData(tx.txDetails))
createMultiSendCallOnlyTx(calls).then(setSafeTx).catch(setSafeTxError)
}, [calls, setSafeTx, setSafeTxError])
}, [batchTxs, setSafeTx, setSafeTxError])

return <SignOrExecuteForm onSubmit={onSubmit} isBatch />
return (
<SignOrExecuteForm onSubmit={onSubmit} isBatch>
{batchTxs.map((item, index) => (
<BatchTxItem key={index} count={index + 1} {...item} />
))}
</SignOrExecuteForm>
)
}

const ConfirmBatchFlow = (props: ConfirmBatchProps) => {
const { length } = useDraftBatch()

return (
<TxLayout
title="Confirm batch"
subtitle={`This batch contains ${props.calls.length} transactions`}
subtitle={`This batch contains ${length} transaction${length > 1 ? 's' : ''}`}
icon={BatchIcon}
step={0}
isBatch
>
<ConfirmBatch {...props} />
</TxLayout>
Expand Down
192 changes: 98 additions & 94 deletions src/components/tx/DecodedTx/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { fireEvent, render } from '@/tests/test-utils'
import { type SafeTransaction } from '@safe-global/safe-core-sdk-types'
import * as gatewayMethods from '@safe-global/safe-gateway-typescript-sdk'
import DecodedTx from '.'
import { waitFor } from '@testing-library/react'

Expand All @@ -24,6 +23,21 @@ describe('DecodedTx', () => {
},
} as SafeTransaction
}
decodedData={{
method: 'Native token transfer',
parameters: [
{
name: 'to',
type: 'address',
value: '0x3430d04E42a722c5Ae52C5Bffbf1F230C2677600',
},
{
name: 'value',
type: 'uint256',
value: '1000000',
},
],
}}
/>,
)

Expand All @@ -37,24 +51,6 @@ describe('DecodedTx', () => {
})

it('should render an ERC20 transfer', async () => {
jest.spyOn(gatewayMethods, 'getDecodedData').mockReturnValue(
Promise.resolve({
method: 'transfer',
parameters: [
{
name: 'to',
type: 'address',
value: '0x474e5Ded6b5D078163BFB8F6dBa355C3aA5478C8',
},
{
name: 'value',
type: 'uint256',
value: '16745726664999765048',
},
],
}),
)

const result = render(
<DecodedTx
tx={
Expand All @@ -73,6 +69,21 @@ describe('DecodedTx', () => {
},
} as SafeTransaction
}
decodedData={{
method: 'transfer',
parameters: [
{
name: 'to',
type: 'address',
value: '0x474e5Ded6b5D078163BFB8F6dBa355C3aA5478C8',
},
{
name: 'value',
type: 'uint256',
value: '16745726664999765048',
},
],
}}
/>,
)

Expand All @@ -88,73 +99,6 @@ describe('DecodedTx', () => {
})

it('should render a multisend transaction', async () => {
jest.spyOn(gatewayMethods, 'getDecodedData').mockReturnValue(
Promise.resolve({
method: 'multiSend',
parameters: [
{
name: 'transactions',
type: 'bytes',
value: '0x0057f1887a8bf19b14fc0df',
valueDecoded: [
{
operation: 0,
to: '0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85',
value: '0',
data: '0x42842e0e0000000000000000000',
dataDecoded: {
method: 'safeTransferFrom',
parameters: [
{
name: 'from',
type: 'address',
value: '0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6',
},
{
name: 'to',
type: 'address',
value: '0x474e5Ded6b5D078163BFB8F6dBa355C3aA5478C8',
},
{
name: 'tokenId',
type: 'uint256',
value: '52964617156216674852059480948658573966398315289847646343083345905048987083870',
},
],
},
},
{
operation: 0,
to: '0xD014e20A75437a4bd0FbB40498FF94e6F337c3e9',
value: '0',
data: '0x42842e0e000000000000000000000000a77de',
dataDecoded: {
method: 'safeTransferFrom',
parameters: [
{
name: 'from',
type: 'address',
value: '0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6',
},
{
name: 'to',
type: 'address',
value: '0x474e5Ded6b5D078163BFB8F6dBa355C3aA5478C8',
},
{
name: 'tokenId',
type: 'uint256',
value: '412',
},
],
},
},
],
},
],
}),
)

const result = render(
<DecodedTx
tx={
Expand All @@ -173,6 +117,70 @@ describe('DecodedTx', () => {
},
} as SafeTransaction
}
decodedData={{
method: 'multiSend',
parameters: [
{
name: 'transactions',
type: 'bytes',
value: '0x0057f1887a8bf19b14fc0df',
valueDecoded: [
{
operation: 0,
to: '0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85',
value: '0',
data: '0x42842e0e0000000000000000000',
dataDecoded: {
method: 'safeTransferFrom',
parameters: [
{
name: 'from',
type: 'address',
value: '0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6',
},
{
name: 'to',
type: 'address',
value: '0x474e5Ded6b5D078163BFB8F6dBa355C3aA5478C8',
},
{
name: 'tokenId',
type: 'uint256',
value: '52964617156216674852059480948658573966398315289847646343083345905048987083870',
},
],
},
},
{
operation: 0,
to: '0xD014e20A75437a4bd0FbB40498FF94e6F337c3e9',
value: '0',
data: '0x42842e0e000000000000000000000000a77de',
dataDecoded: {
method: 'safeTransferFrom',
parameters: [
{
name: 'from',
type: 'address',
value: '0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6',
},
{
name: 'to',
type: 'address',
value: '0x474e5Ded6b5D078163BFB8F6dBa355C3aA5478C8',
},
{
name: 'tokenId',
type: 'uint256',
value: '412',
},
],
},
},
],
},
],
}}
/>,
)

Expand All @@ -185,14 +193,6 @@ describe('DecodedTx', () => {
})

it('should render a function call without parameters', async () => {
// Wrapped token deposit function
jest.spyOn(gatewayMethods, 'getDecodedData').mockReturnValue(
Promise.resolve({
method: 'deposit',
parameters: [],
}),
)

const result = render(
<DecodedTx
tx={
Expand All @@ -211,6 +211,10 @@ describe('DecodedTx', () => {
},
} as SafeTransaction
}
decodedData={{
method: 'deposit',
parameters: [],
}}
/>,
)

Expand Down
Loading

0 comments on commit 3edb2c9

Please sign in to comment.