Skip to content

Commit

Permalink
Merge pull request #140 from multiversx/rt/fix/data-decode
Browse files Browse the repository at this point in the history
Updated DataDecode.tsx to used sdk-dapp decode functions
  • Loading branch information
radumojic authored Dec 5, 2024
2 parents 321fcfb + 25d9329 commit fa5155e
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 232 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@fortawesome/free-solid-svg-icons": "6.5.1",
"@fortawesome/react-fontawesome": "0.2.0",
"@multiversx/sdk-core": "13.15.0",
"@multiversx/sdk-dapp": "3.0.10",
"@multiversx/sdk-dapp": "3.0.11",
"@multiversx/sdk-dapp-sc-explorer": "0.0.2-beta.0",
"@react-three/fiber": "8.17.6",
"@reduxjs/toolkit": "1.9.5",
Expand Down
190 changes: 3 additions & 187 deletions src/components/DataDecode/DataDecode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,197 +6,12 @@ import {
useState
} from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import BigNumber from 'bignumber.js';
import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import { decodeForDisplay } from '@multiversx/sdk-dapp/utils/transactions/transactionInfoHelpers/decodeForDisplay';
import { Anchor, Dropdown } from 'react-bootstrap';
import { MAX_DECODE_TX_DATA_LENGTH } from 'appConstants';
import { CopyButton } from 'components';
import { addressIsBech32, bech32, isUtf8 } from 'helpers';
import { faExclamationTriangle } from 'icons/regular';
import { TransactionTokensType } from 'types';

export enum DecodeMethodEnum {
raw = 'raw',
text = 'text',
decimal = 'decimal',
smart = 'smart'
}

export const decode = (
part: string,
decodeMethod: DecodeMethodEnum,
transactionTokens?: TransactionTokensType
) => {
switch (decodeMethod) {
case DecodeMethodEnum.text:
try {
return Buffer.from(String(part), 'hex').toString('utf8');
} catch {}
return part;
case DecodeMethodEnum.decimal:
return part !== '' ? new BigNumber(part, 16).toString(10) : '';
case DecodeMethodEnum.smart:
try {
const bech32Encoded = bech32.encode(part);
if (addressIsBech32(bech32Encoded)) {
return bech32Encoded;
}
} catch {}
try {
const decoded = Buffer.from(String(part), 'hex').toString('utf8');
if (!isUtf8(decoded)) {
if (transactionTokens) {
const tokens = [
...transactionTokens.esdts,
...transactionTokens.nfts
];
if (tokens.some((token) => decoded.includes(token))) {
return decoded;
}
}
const bn = new BigNumber(part, 16);
return bn.toString(10);
} else {
return decoded;
}
} catch {}
return part;
case DecodeMethodEnum.raw:
default:
return part;
}
};

const treatSmartDecodingCases = ({
parts,
decodedParts,
identifier
}: {
parts: string[];
decodedParts: string[];
identifier?: string;
}) => {
const updatedParts = [...decodedParts];

if (parts[0] === 'ESDTNFTTransfer' && parts[2]) {
updatedParts[2] = decode(parts[2], DecodeMethodEnum.decimal);
}
if (identifier === 'ESDTNFTTransfer' && parts[1]) {
const base64Buffer = Buffer.from(String(parts[1]), 'base64');
updatedParts[1] = decode(
base64Buffer.toString('hex'),
DecodeMethodEnum.decimal
);
}

return updatedParts;
};

export const decodeForDisplay = ({
input,
decodeMethod,
identifier
}: {
input: string;
decodeMethod: DecodeMethodEnum;
identifier?: string;
}) => {
const display: {
displayValue: string;
validationWarnings: string[];
} = {
displayValue: '',
validationWarnings: []
};

const getDecodedParts = (parts: string[]) => {
const initialDecodedParts = parts.map((part, index) => {
if (
parts.length >= 2 &&
((index === 0 && part.length < 64) || (index === 1 && !parts[0]))
) {
const encodedDisplayValue = /[^a-z0-9]/gi.test(part);
if (encodedDisplayValue) {
return decode(part, decodeMethod);
} else {
return part;
}
} else {
const hexValidationWarnings = getHexValidationWarnings(part);
if (hexValidationWarnings.length) {
display.validationWarnings = Array.from(
new Set([...display.validationWarnings, ...hexValidationWarnings])
);
}

return decode(part, decodeMethod);
}
});

const decodedParts =
decodeMethod === 'smart'
? treatSmartDecodingCases({
parts,
decodedParts: initialDecodedParts,
identifier
})
: initialDecodedParts;

return decodedParts;
};

if (input.includes('@') || input.includes('\n')) {
if (input.includes('@')) {
const parts = input.split('@');
const decodedParts = getDecodedParts(parts);
display.displayValue = decodedParts.join('@');
}
if (input.includes('\n')) {
const parts = input.split('\n');
const initialDecodedParts = parts.map((part) => {
const base64Buffer = Buffer.from(String(part), 'base64');
if (decodeMethod === DecodeMethodEnum.raw) {
return part;
} else {
return decode(base64Buffer.toString('hex'), decodeMethod);
}
});

const decodedParts =
decodeMethod === 'smart'
? treatSmartDecodingCases({
parts,
decodedParts: initialDecodedParts,
identifier
})
: initialDecodedParts;

display.displayValue = decodedParts.join('\n');
}
} else {
display.displayValue = decode(input, decodeMethod);
}

return display;
};

const isHexValidCharacters = (str: string) => {
return str.toLowerCase().match(/[0-9a-f]/g);
};
const isHexValidLength = (str: string) => {
return str.length % 2 === 0;
};

const getHexValidationWarnings = (str: string) => {
const warnings = [];
if (str && !isHexValidCharacters(str)) {
warnings.push(`Invalid Hex characters on argument @${str}`);
}
if (str && !isHexValidLength(str)) {
warnings.push(`Odd number of Hex characters on argument @${str}`);
}

return warnings;
};

export const DataDecode = ({
value,
Expand Down Expand Up @@ -267,6 +82,7 @@ export const DataDecode = ({
<div className='d-flex button-holder'>
<CopyButton text={displayValue} className='copy-button' />
<Dropdown
id='dataDecodeTypeDropdown'
className='position-absolute'
onSelect={handleSelect}
onToggle={(e) => {
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/urlFilters/useGetTransactionDecodeFilters.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { stringIsInteger } from '@multiversx/sdk-dapp/utils/validation/stringIsInteger';
import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import { useSearchParams } from 'react-router-dom';

import { DecodeMethodEnum } from 'components/DataDecode';

const checkType = (type: string) =>
type && Object.keys(DecodeMethodEnum).includes(type)
? (type as DecodeMethodEnum)
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/urlFilters/useGetTransactionUrlHashParams.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useLocation } from 'react-router-dom';

import { DecodeMethodEnum } from 'components/DataDecode';
import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import { useGetTransactionDecodeFilters } from 'hooks';

export interface TransactionDecodeParamsType {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { useEffect, useState } from 'react';
import { Anchorme } from 'react-anchorme';
import { useLocation, useNavigate } from 'react-router-dom';

import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import { MAX_DISPLAY_TX_DATA_LENGTH } from 'appConstants';
import { DetailItem, ModalLink, DataDecode } from 'components';
import { DecodeMethodEnum } from 'components/DataDecode';
import { truncate } from 'helpers';
import {
useScamFlag,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { useRef, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import classNames from 'classnames';

import {
CopyButton,
DataDecode,
DecodeMethodEnum,
AccountLink,
NetworkLink
} from 'components';
import { CopyButton, DataDecode, AccountLink, NetworkLink } from 'components';
import { urlBuilder } from 'helpers';
import {
useActiveRoute,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useRef, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import classNames from 'classnames';
import { useSearchParams } from 'react-router-dom';

import { MAX_DISPLAY_TX_DATA_LENGTH } from 'appConstants';
import {
CopyButton,
DataDecode,
DecodeMethodEnum,
AccountLink,
NetworkLink,
DetailItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

import { DecodeMethodEnum } from '@multiversx/sdk-dapp/types';
import { decodeForDisplay } from '@multiversx/sdk-dapp/utils/transactions/transactionInfoHelpers/decodeForDisplay';
import { InfoTooltip, NetworkLink } from 'components';
import { decodeForDisplay, DecodeMethodEnum } from 'components/DataDecode';
import {
getTransactionMessages,
capitalizeFirstLetter,
Expand Down
Loading

0 comments on commit fa5155e

Please sign in to comment.