Skip to content

Commit

Permalink
feat: resolve function name of ExecutionFailure in transaction detail
Browse files Browse the repository at this point in the history
  • Loading branch information
coldnight committed Jun 14, 2022
1 parent 6476b36 commit 12e3faa
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 87 deletions.
3 changes: 2 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"StateRootHash": "State Root Hash",
"Status": "Status",
"Sender": "Sender",
"FailureFunctionName": "Executtion Failure Function",
"FunctionModuleAddress": "Contract Address",
"FunctionModuleName": "Module Name",
"FunctionName": "Function Name",
Expand Down Expand Up @@ -176,4 +177,4 @@
"holderList": "Token Holders List",
"transactionList": "Token Transactions List"
}
}
}
3 changes: 2 additions & 1 deletion public/locales/zh/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"StateRootHash": "根哈希",
"Status": "状态",
"Sender": "发送方",
"FailureFunctionName": "执行失败函数名",
"FunctionModuleAddress": "合约地址",
"FunctionModuleName": "模块名",
"FunctionName": "函数名",
Expand Down Expand Up @@ -176,4 +177,4 @@
"holderList": "代币持有者列表",
"transactionList": "代币交易列表"
}
}
}
3 changes: 2 additions & 1 deletion src/modules/Transactions/components/Detail/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ const selector = createSelector(

export default connect(selector, {
getTransaction: actions.getTransaction,
})(Index as any) as any;
getModuleFunctionIndex: actions.getModuleFunctionIndex,
})(Index as any) as any;
182 changes: 102 additions & 80 deletions src/modules/Transactions/components/Detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from '@starcoin/starcoin';
import { arrayify } from '@ethersproject/bytes';
import get from 'lodash/get';
import {toObject } from '@/utils/helper';
import { toObject } from '@/utils/helper';
import useSWR from 'swr';
import FileSaver from 'file-saver';
import { GetApp } from '@mui/icons-material';
Expand All @@ -29,7 +29,7 @@ import Loading from '@/common/Loading';
import EventViewTable from '@/common/View/EventViewTable';
import PageView from '@/common/View/PageView';
import CommonLink from '@/common/Link';
import { withRouter,RoutedProps } from '@/utils/withRouter';
import { withRouter, RoutedProps } from '@/utils/withRouter';



Expand All @@ -43,9 +43,9 @@ function formatArgsWithTypeTag(
switch (typeTag) {
case 'Signer':
case 'Address': {
let decodeAddress:string='0x';
for(let i=0;i<16;i++){
decodeAddress+=deserializer.deserializeU8().toString(16);
let decodeAddress: string = '0x';
for (let i = 0; i < 16; i++) {
decodeAddress += deserializer.deserializeU8().toString(16);
}
return decodeAddress;
}
Expand Down Expand Up @@ -74,15 +74,13 @@ function formatArgsWithTypeTag(
// return hexlify(deserializer.deserializeBytes());
}
if ('Struct' in typeTag) {
return `${typeTag.Struct.address}::${typeTag.Struct.module}::${
typeTag.Struct.name
}${
typeTag.Struct.type_params
return `${typeTag.Struct.address}::${typeTag.Struct.module}::${typeTag.Struct.name
}${typeTag.Struct.type_params
? `<${typeTag.Struct.type_params
.map((param) => formatArgsWithTypeTag(deserializer, param))
.join(', ')}>`
: ''
}`;
}`;
}
return undefined;
} catch {
Expand All @@ -105,10 +103,10 @@ export function useResolveFunction(functionId?: string, network?: string) {
}

const DecodedPayloadContent = ({
network,
txnPayload,
alt,
}: {
network,
txnPayload,
alt,
}: {
network: string;
alt: string;
txnPayload: any;
Expand All @@ -135,11 +133,10 @@ const DecodedPayloadContent = ({
const decodedArgs = args ? args.map((arg: string, index: number) => {
const type_tag = resolvedFunction?.args[index + 1]?.type_tag;
return resolvedFunction?.args[index + 1]
? `${types.formatTypeTag(resolvedFunction.args[index + 1]?.type_tag)}: ${
type_tag !== 'Address' ? formatArgsWithTypeTag(
new bcs.BcsDeserializer(arrayify(arg)),
resolvedFunction.args[index + 1]?.type_tag,
) : arg
? `${types.formatTypeTag(resolvedFunction.args[index + 1]?.type_tag)}: ${type_tag !== 'Address' ? formatArgsWithTypeTag(
new bcs.BcsDeserializer(arrayify(arg)),
resolvedFunction.args[index + 1]?.type_tag,
) : arg
}`
: arg;
}) : {};
Expand Down Expand Up @@ -176,7 +173,7 @@ const useStyles = (theme: any) =>
rawData: {
wordBreak: 'break-all',
overflow: 'auto',
fontSize:theme.spacing(1)
fontSize: theme.spacing(1)
},

accordion: {
Expand All @@ -189,8 +186,8 @@ const useStyles = (theme: any) =>
csvExportIcon: {
verticalAlign: 'middle',
},
card:{
marginTop:theme.spacing(2),
card: {
marginTop: theme.spacing(2),
display: 'flex',
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[800] : undefined,
color: theme.palette.getContrastText(theme.palette.background.paper),
Expand All @@ -200,31 +197,34 @@ const useStyles = (theme: any) =>

interface IndexState {
resolvedFunction: any;
tabSelect:number,
tabSelect: number,
}

interface IndexProps extends RoutedProps {
interface IndexProps extends RoutedProps {
classes: any;
t: any;
match: any;
transaction: any;
failureFunction: any;
getTransaction: (data: any, callback?: any) => any;
getModuleFunctionIndex: (data: any, callback?: any) => any;
}

class Index extends PureComponent<IndexProps, IndexState> {
// eslint-disable-next-line react/static-property-placement
static defaultProps = {
match: {},
transaction: null,
failureFunction: null,
getTransaction: () => {
},
};

constructor(props: IndexProps) {
super(props);
this.state = {
resolvedFunction:undefined,
tabSelect:0,
resolvedFunction: undefined,
tabSelect: 0,
};
}

Expand All @@ -234,6 +234,22 @@ class Index extends PureComponent<IndexProps, IndexState> {
this.props.getTransaction({ hash });
}

componentDidUpdate(prevProps: IndexProps) {
if (prevProps.failureFunction == null && this.props.transaction.status !== "Executed") {
try {
const status = JSON.parse(this.props.transaction.status);
if (status.ExecutionFailure !== undefined) {
const st = status.ExecutionFailure;
const moduleId = `${st.location.Module.address}::${st.location.Module.name}`;
const index = st.function;
this.props.getModuleFunctionIndex({ moduleId, index });
}
} catch (e) {
console.log(e);
}
}
}

generateExtraTabs() {
const { transaction, classes, t, params } = this.props;
const network = params.network;
Expand Down Expand Up @@ -297,42 +313,42 @@ class Index extends PureComponent<IndexProps, IndexState> {
<Typography variant='body1'>{t('transaction.NoRawData')}</Typography>
);
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
this.setState({tabSelect:newValue});
this.setState({ tabSelect: newValue });
};

return (<Card className={classes.card}>
<Box sx={{ width: '100%' }}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }} >
<Tabs value={this.state.tabSelect} onChange={handleChange} aria-label="basic tabs example">
<Tab label={t('header.events')} {...a11yProps(0)} />
<Tab label= {t('transaction.RawData')} {...a11yProps(1)} />
<Tab label= {t('transaction.decodedPayload')} {...a11yProps(2)} />
</Tabs>
</Box>
<ScanTabPanel value={this.state.tabSelect} index={0}>
{isInitialLoad ? <Loading /> : eventsContent}
</ScanTabPanel>
<ScanTabPanel value={this.state.tabSelect} index={1}>
<div className={classes.rawData}>
{isInitialLoad ? <Loading /> : rawContent}
</div>
</ScanTabPanel>
<ScanTabPanel value={this.state.tabSelect} index={2}>
<div className={classes.rawData}>
{isInitialLoad ? (
<Loading />
) : (
<DecodedPayloadContent
network={network}
alt={t('transaction.NoDecodedPayload')}
txnPayload={txnPayload}
/>
)}
</div>
</ScanTabPanel>

<Box sx={{ width: '100%' }}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }} >
<Tabs value={this.state.tabSelect} onChange={handleChange} aria-label="basic tabs example">
<Tab label={t('header.events')} {...a11yProps(0)} />
<Tab label={t('transaction.RawData')} {...a11yProps(1)} />
<Tab label={t('transaction.decodedPayload')} {...a11yProps(2)} />
</Tabs>
</Box>
</Card>);
<ScanTabPanel value={this.state.tabSelect} index={0}>
{isInitialLoad ? <Loading /> : eventsContent}
</ScanTabPanel>
<ScanTabPanel value={this.state.tabSelect} index={1}>
<div className={classes.rawData}>
{isInitialLoad ? <Loading /> : rawContent}
</div>
</ScanTabPanel>
<ScanTabPanel value={this.state.tabSelect} index={2}>
<div className={classes.rawData}>
{isInitialLoad ? (
<Loading />
) : (
<DecodedPayloadContent
network={network}
alt={t('transaction.NoDecodedPayload')}
txnPayload={txnPayload}
/>
)}
</div>
</ScanTabPanel>

</Box>
</Card>);
}

render() {
Expand Down Expand Up @@ -442,7 +458,7 @@ class Index extends PureComponent<IndexProps, IndexState> {
this.setState({ resolvedFunction: data });
};
const resolvedFunction = this.state?.resolvedFunction;
if (!resolvedFunction){
if (!resolvedFunction) {
getResolvedFunction();
}

Expand All @@ -451,10 +467,10 @@ class Index extends PureComponent<IndexProps, IndexState> {
const type_tag = resolvedFunction?.args[index + 1]?.type_tag;
return resolvedFunction?.args[index + 1]
? [types.formatTypeTag(type_tag),
type_tag !== 'Address' ? formatArgsWithTypeTag(
new bcs.BcsDeserializer(arrayify(arg)),
resolvedFunction.args[index + 1].type_tag,
) : arg,
type_tag !== 'Address' ? formatArgsWithTypeTag(
new bcs.BcsDeserializer(arrayify(arg)),
resolvedFunction.args[index + 1].type_tag,
) : arg,
]
: arg;
}) : {};
Expand Down Expand Up @@ -491,13 +507,19 @@ class Index extends PureComponent<IndexProps, IndexState> {
// [t('common.Time'), new Date(parseInt(blockTime, 10)).toLocaleString()],
[t('transaction.StateRootHash'), source.state_root_hash],
[t('transaction.Status'), source.status],
[t('common.GasUsed'), source.gas_used],
[
t('transaction.Sender'),
<CommonLink path={`/${network}/address/${sender}`} title={sender} />,
],

];

if (this.props.failureFunction !== null) {
columns.push([t('transaction.FailureFunctionName'), this.props.failureFunction.name]);
}

columns.push([t('common.GasUsed'), source.gas_used]);
columns.push([
t('transaction.Sender'),
<CommonLink path={`/${network}/address/${sender}`} title={sender} />,
])

if (moduleAddress) {
columns.push([t('transaction.FunctionModuleAddress'), moduleAddress]);
}
Expand Down Expand Up @@ -528,9 +550,9 @@ class Index extends PureComponent<IndexProps, IndexState> {
const savData = [
[t('common.Hash'), source.transaction_hash],
[t('transaction.Type'), type],
[t('common.Time'),`${new Date(parseInt(source.timestamp, 10)).toLocaleString()} ${new Date().toTimeString().slice(9)}`],
[t('transaction.BlockHash'),source.block_hash],
[t('transaction.BlockHeight'),source.block_number],
[t('common.Time'), `${new Date(parseInt(source.timestamp, 10)).toLocaleString()} ${new Date().toTimeString().slice(9)}`],
[t('transaction.BlockHash'), source.block_hash],
[t('transaction.BlockHeight'), source.block_number],
[t('transaction.StateRootHash'), source.state_root_hash],
[t('transaction.Status'), source.status],
[t('common.GasUsed'), source.gas_used],
Expand All @@ -549,13 +571,13 @@ class Index extends PureComponent<IndexProps, IndexState> {
if (txn_type_args) {
savData.push([t('transaction.TxnTypeArgs'), JSON.stringify(txn_type_args[0] || [])]);
}

for (let i = 0; i < decodedArgs.length; i++) {
if (decodedArgs[i][0] === 'address') {
const address = decodedArgs[i][1];
savData.push([`${t('transaction.arg')} ${i+1}`,address]);
savData.push([`${t('transaction.arg')} ${i + 1}`, address]);
} else {
savData.push([`${t('transaction.arg')} ${i+1}`, decodedArgs[i][1]]);
savData.push([`${t('transaction.arg')} ${i + 1}`, decodedArgs[i][1]]);
}
}

Expand All @@ -568,21 +590,21 @@ class Index extends PureComponent<IndexProps, IndexState> {
csvRow += `"${element[1]}",`;
}
csvData = `${csvTitle}\r\n${csvRow}`;
const blob = new Blob([csvData], {type: "text/plain;charset=utf-8"});
const blob = new Blob([csvData], { type: "text/plain;charset=utf-8" });
FileSaver.saveAs(blob, `${source.transaction_hash}.csv`);

}

columns.push([
``,
<div className={this.props.classes.csvExport}>
[<Button onClick={()=>{csvExport()}}>
Download CSV Export
</Button>
[<Button onClick={() => { csvExport() }}>
Download CSV Export
</Button>
<GetApp className={this.props.classes.csvExportIcon} />]
</div>
]);



return (
Expand All @@ -599,4 +621,4 @@ class Index extends PureComponent<IndexProps, IndexState> {
}
}

export default withStyles(useStyles)(withTranslation()(withRouter(Index)) );
export default withStyles(useStyles)(withTranslation()(withRouter(Index)));
Loading

0 comments on commit 12e3faa

Please sign in to comment.