Commit fd459373 authored by isstuev's avatar isstuev

add method call as tx interpretation

parent 623f414c
...@@ -18,9 +18,10 @@ export type TxInterpretationVariable = ...@@ -18,9 +18,10 @@ export type TxInterpretationVariable =
TxInterpretationVariableTimestamp | TxInterpretationVariableTimestamp |
TxInterpretationVariableToken | TxInterpretationVariableToken |
TxInterpretationVariableAddress | TxInterpretationVariableAddress |
TxInterpretationVariableDomain; TxInterpretationVariableDomain |
TxInterpretationVariableMethod;
export type TxInterpretationVariableType = 'string' | 'currency' | 'timestamp' | 'token' | 'address' | 'domain'; export type TxInterpretationVariableType = 'string' | 'currency' | 'timestamp' | 'token' | 'address' | 'domain' | 'method';
export type TxInterpretationVariableString = { export type TxInterpretationVariableString = {
type: 'string'; type: 'string';
...@@ -51,3 +52,8 @@ export type TxInterpretationVariableDomain = { ...@@ -51,3 +52,8 @@ export type TxInterpretationVariableDomain = {
type: 'domain'; type: 'domain';
value: string; value: string;
} }
export type TxInterpretationVariableMethod = {
type: 'method';
value: string;
}
...@@ -83,7 +83,7 @@ const TransactionPageContent = () => { ...@@ -83,7 +83,7 @@ const TransactionPageContent = () => {
}; };
}, [ appProps.referrer ]); }, [ appProps.referrer ]);
const titleSecondRow = <TxSubHeading hash={ hash } hasTag={ Boolean(data?.tx_tag) }/>; const titleSecondRow = <TxSubHeading hash={ hash } hasTag={ Boolean(data?.tx_tag) } txQuery={ txQuery }/>;
const content = (() => { const content = (() => {
if (isPlaceholderData && !showDegradedView) { if (isPlaceholderData && !showDegradedView) {
......
import { test, expect } from '@playwright/experimental-ct-react'; import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react'; import React from 'react';
import * as txMock from 'mocks/txs/tx';
import { txInterpretation } from 'mocks/txs/txInterpretation'; import { txInterpretation } from 'mocks/txs/txInterpretation';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs'; import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import TestApp from 'playwright/TestApp'; import TestApp from 'playwright/TestApp';
...@@ -8,15 +9,22 @@ import buildApiUrl from 'playwright/utils/buildApiUrl'; ...@@ -8,15 +9,22 @@ import buildApiUrl from 'playwright/utils/buildApiUrl';
import * as configs from 'playwright/utils/configs'; import * as configs from 'playwright/utils/configs';
import TxSubHeading from './TxSubHeading'; import TxSubHeading from './TxSubHeading';
import type { TxQuery } from './useTxQuery';
const hash = '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3193'; const hash = '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3193';
const TX_INTERPRETATION_API_URL = buildApiUrl('tx_interpretation', { hash }); const TX_INTERPRETATION_API_URL = buildApiUrl('tx_interpretation', { hash });
const txQuery = {
data: txMock.base,
isPlaceholderData: false,
isError: false,
} as TxQuery;
test('no interpretation +@mobile', async({ mount }) => { test('no interpretation +@mobile', async({ mount }) => {
const component = await mount( const component = await mount(
<TestApp> <TestApp>
<TxSubHeading hash={ hash } hasTag={ false }/> <TxSubHeading hash={ hash } hasTag={ false } txQuery={ txQuery }/>
</TestApp>, </TestApp>,
); );
...@@ -36,7 +44,7 @@ bsInterpretationTest('with interpretation +@mobile +@dark-mode', async({ mount, ...@@ -36,7 +44,7 @@ bsInterpretationTest('with interpretation +@mobile +@dark-mode', async({ mount,
const component = await mount( const component = await mount(
<TestApp> <TestApp>
<TxSubHeading hash={ hash } hasTag={ false }/> <TxSubHeading hash={ hash } hasTag={ false } txQuery={ txQuery }/>
</TestApp>, </TestApp>,
); );
...@@ -51,7 +59,22 @@ bsInterpretationTest('with interpretation and view all link +@mobile', async({ m ...@@ -51,7 +59,22 @@ bsInterpretationTest('with interpretation and view all link +@mobile', async({ m
const component = await mount( const component = await mount(
<TestApp> <TestApp>
<TxSubHeading hash={ hash } hasTag={ false }/> <TxSubHeading hash={ hash } hasTag={ false } txQuery={ txQuery }/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
bsInterpretationTest('no interpretation, has method called', async({ mount, page }) => {
await page.route(TX_INTERPRETATION_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify({ data: { summaries: [] } }),
}));
const component = await mount(
<TestApp>
<TxSubHeading hash={ hash } hasTag={ false } txQuery={ txQuery }/>
</TestApp>, </TestApp>,
); );
...@@ -59,6 +82,11 @@ bsInterpretationTest('with interpretation and view all link +@mobile', async({ m ...@@ -59,6 +82,11 @@ bsInterpretationTest('with interpretation and view all link +@mobile', async({ m
}); });
bsInterpretationTest('no interpretation', async({ mount, page }) => { bsInterpretationTest('no interpretation', async({ mount, page }) => {
const txPendingQuery = {
data: txMock.pending,
isPlaceholderData: false,
isError: false,
} as TxQuery;
await page.route(TX_INTERPRETATION_API_URL, (route) => route.fulfill({ await page.route(TX_INTERPRETATION_API_URL, (route) => route.fulfill({
status: 200, status: 200,
body: JSON.stringify({ data: { summaries: [] } }), body: JSON.stringify({ data: { summaries: [] } }),
...@@ -66,7 +94,7 @@ bsInterpretationTest('no interpretation', async({ mount, page }) => { ...@@ -66,7 +94,7 @@ bsInterpretationTest('no interpretation', async({ mount, page }) => {
const component = await mount( const component = await mount(
<TestApp> <TestApp>
<TxSubHeading hash={ hash } hasTag={ false }/> <TxSubHeading hash={ hash } hasTag={ false } txQuery={ txPendingQuery }/>
</TestApp>, </TestApp>,
); );
......
...@@ -10,12 +10,15 @@ import NetworkExplorers from 'ui/shared/NetworkExplorers'; ...@@ -10,12 +10,15 @@ import NetworkExplorers from 'ui/shared/NetworkExplorers';
import { TX_ACTIONS_BLOCK_ID } from 'ui/tx/details/txDetailsActions/TxDetailsActionsWrapper'; import { TX_ACTIONS_BLOCK_ID } from 'ui/tx/details/txDetailsActions/TxDetailsActionsWrapper';
import TxInterpretation from 'ui/tx/interpretation/TxInterpretation'; import TxInterpretation from 'ui/tx/interpretation/TxInterpretation';
import type { TxQuery } from './useTxQuery';
type Props = { type Props = {
hash?: string; hash?: string;
hasTag: boolean; hasTag: boolean;
txQuery: TxQuery;
} }
const TxSubHeading = ({ hash, hasTag }: Props) => { const TxSubHeading = ({ hash, hasTag, txQuery }: Props) => {
const hasInterpretationFeature = config.features.txInterpretation.isEnabled; const hasInterpretationFeature = config.features.txInterpretation.isEnabled;
const txInterpretationQuery = useApiQuery('tx_interpretation', { const txInterpretationQuery = useApiQuery('tx_interpretation', {
...@@ -26,15 +29,15 @@ const TxSubHeading = ({ hash, hasTag }: Props) => { ...@@ -26,15 +29,15 @@ const TxSubHeading = ({ hash, hasTag }: Props) => {
}, },
}); });
const hasInterpretation = hasInterpretationFeature && const content = (() => {
const hasInterpretation = hasInterpretationFeature &&
(txInterpretationQuery.isPlaceholderData || Boolean(txInterpretationQuery.data?.data.summaries.length)); (txInterpretationQuery.isPlaceholderData || Boolean(txInterpretationQuery.data?.data.summaries.length));
const hasViewAllInterpretationsLink = const hasViewAllInterpretationsLink =
!txInterpretationQuery.isPlaceholderData && txInterpretationQuery.data?.data.summaries && txInterpretationQuery.data?.data.summaries.length > 1; !txInterpretationQuery.isPlaceholderData && txInterpretationQuery.data?.data.summaries && txInterpretationQuery.data?.data.summaries.length > 1;
return ( if (hasInterpretation) {
<Box display={{ base: 'block', lg: 'flex' }} alignItems="center" w="100%"> return (
{ hasInterpretation && (
<Flex mr={{ base: 0, lg: 6 }} flexWrap="wrap" alignItems="center"> <Flex mr={{ base: 0, lg: 6 }} flexWrap="wrap" alignItems="center">
<TxInterpretation <TxInterpretation
summary={ txInterpretationQuery.data?.data.summaries[0] } summary={ txInterpretationQuery.data?.data.summaries[0] }
...@@ -43,10 +46,41 @@ const TxSubHeading = ({ hash, hasTag }: Props) => { ...@@ -43,10 +46,41 @@ const TxSubHeading = ({ hash, hasTag }: Props) => {
mr={ hasViewAllInterpretationsLink ? 3 : 0 } mr={ hasViewAllInterpretationsLink ? 3 : 0 }
/> />
{ hasViewAllInterpretationsLink && { hasViewAllInterpretationsLink &&
<Link href={ `#${ TX_ACTIONS_BLOCK_ID }` }>View all</Link> } <Link href={ `#${ TX_ACTIONS_BLOCK_ID }` }>View all</Link> }
</Flex> </Flex>
) } );
{ !hasInterpretation && <TxEntity hash={ hash } noLink noCopy={ false } fontWeight={ 500 } mr={{ base: 0, lg: 2 }} fontFamily="heading"/> } } else if (hasInterpretationFeature && txQuery.data?.method && txQuery.data?.from && txQuery.data?.to) {
return (
<TxInterpretation
summary={{
summary_template: `{sender_hash} called {method} on {receiver_hash}`,
summary_template_variables: {
sender_hash: {
type: 'address',
value: txQuery.data.from,
},
method: {
type: 'method',
value: txQuery.data.method,
},
receiver_hash: {
type: 'address',
value: txQuery.data.to,
},
},
}}
isLoading={ txQuery.isPlaceholderData }
fontSize="lg"
/>
);
} else {
return <TxEntity hash={ hash } noLink noCopy={ false } fontWeight={ 500 } mr={{ base: 0, lg: 2 }} fontFamily="heading"/>;
}
})();
return (
<Box display={{ base: 'block', lg: 'flex' }} alignItems="center" w="100%">
{ content }
<Flex alignItems="center" justifyContent={{ base: 'start', lg: 'space-between' }} flexGrow={ 1 }> <Flex alignItems="center" justifyContent={{ base: 'start', lg: 'space-between' }} flexGrow={ 1 }>
{ !hasTag && <AccountActionsMenu mr={ 3 } mt={{ base: 3, lg: 0 }}/> } { !hasTag && <AccountActionsMenu mr={ 3 } mt={{ base: 3, lg: 0 }}/> }
<NetworkExplorers type="tx" pathParam={ hash } ml={{ base: 0, lg: 'auto' }} mt={{ base: 3, lg: 0 }}/> <NetworkExplorers type="tx" pathParam={ hash } ml={{ base: 0, lg: 'auto' }} mt={{ base: 3, lg: 0 }}/>
......
...@@ -12,6 +12,7 @@ import config from 'configs/app'; ...@@ -12,6 +12,7 @@ import config from 'configs/app';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import Tag from 'ui/shared/chakra/Tag';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import EnsEntity from 'ui/shared/entities/ens/EnsEntity'; import EnsEntity from 'ui/shared/entities/ens/EnsEntity';
import TokenEntity from 'ui/shared/entities/token/TokenEntity'; import TokenEntity from 'ui/shared/entities/token/TokenEntity';
...@@ -105,6 +106,19 @@ const TxInterpretationElementByType = ({ variable }: { variable?: NonStringTxInt ...@@ -105,6 +106,19 @@ const TxInterpretationElementByType = ({ variable }: { variable?: NonStringTxInt
case 'timestamp': { case 'timestamp': {
return <chakra.span color="text_secondary" whiteSpace="pre">{ dayjs(Number(value) * 1000).format('MMM DD YYYY') }</chakra.span>; return <chakra.span color="text_secondary" whiteSpace="pre">{ dayjs(Number(value) * 1000).format('MMM DD YYYY') }</chakra.span>;
} }
case 'method': {
return (
<Tag
colorScheme={ value === 'Multicall' ? 'teal' : 'gray' }
isTruncated
ml={ 1 }
mr={ 2 }
verticalAlign="text-top"
>
{ value }
</Tag>
);
}
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment