mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
write to contract
This commit is contained in:
@@ -70,6 +70,11 @@ function makePolicyMap() {
|
||||
|
||||
// ad
|
||||
'request-global.czilladx.com',
|
||||
|
||||
// walletconnect
|
||||
'*.walletconnect.com',
|
||||
'wss://*.bridge.walletconnect.org',
|
||||
'wss://www.walletlink.org',
|
||||
],
|
||||
|
||||
'script-src': [
|
||||
@@ -130,6 +135,9 @@ function makePolicyMap() {
|
||||
// ad
|
||||
'servedbyadbutler.com',
|
||||
'cdn.coinzilla.io',
|
||||
|
||||
// walletconnect
|
||||
'*.walletconnect.com',
|
||||
],
|
||||
|
||||
'font-src': [
|
||||
|
||||
+1
-49
@@ -1,16 +1,8 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||
import {
|
||||
EthereumClient,
|
||||
modalConnectors,
|
||||
walletConnectProvider,
|
||||
} from '@web3modal/ethereum';
|
||||
import { Web3Modal } from '@web3modal/react';
|
||||
import type { AppProps } from 'next/app';
|
||||
import React, { useState } from 'react';
|
||||
import type { Chain } from 'wagmi';
|
||||
import { configureChains, createClient, WagmiConfig } from 'wagmi';
|
||||
|
||||
import appConfig from 'configs/app/config';
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
@@ -23,39 +15,6 @@ import theme from 'theme';
|
||||
import AppError from 'ui/shared/AppError/AppError';
|
||||
import ErrorBoundary from 'ui/shared/ErrorBoundary';
|
||||
|
||||
export const poa: Chain = {
|
||||
id: 99,
|
||||
name: 'POA',
|
||||
network: 'poa',
|
||||
nativeCurrency: {
|
||||
decimals: 18,
|
||||
name: 'POA',
|
||||
symbol: 'POA',
|
||||
},
|
||||
rpcUrls: {
|
||||
'default': { http: [ 'https://core.poa.network' ] },
|
||||
},
|
||||
blockExplorers: {
|
||||
'default': { name: 'Blockscout', url: 'https://blockscout.com/poa/core' },
|
||||
},
|
||||
};
|
||||
|
||||
const chains = [ poa ];
|
||||
|
||||
const PROJECT_ID = 'b4ed81be141093911032944632465175';
|
||||
// Wagmi client
|
||||
const { provider } = configureChains(chains, [
|
||||
walletConnectProvider({ projectId: PROJECT_ID }),
|
||||
]);
|
||||
const wagmiClient = createClient({
|
||||
autoConnect: true,
|
||||
connectors: modalConnectors({ appName: 'web3Modal', chains }),
|
||||
provider,
|
||||
});
|
||||
|
||||
// Web3Modal Ethereum Client
|
||||
const ethereumClient = new EthereumClient(wagmiClient, chains);
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
useConfigSentry();
|
||||
const [ queryClient ] = useState(() => new QueryClient({
|
||||
@@ -102,14 +61,7 @@ function MyApp({ Component, pageProps }: AppProps) {
|
||||
<QueryClientProvider client={ queryClient }>
|
||||
<ScrollDirectionProvider>
|
||||
<SocketProvider url={ `${ appConfig.api.socket }${ appConfig.api.basePath }/socket/v2` }>
|
||||
<WagmiConfig client={ wagmiClient }>
|
||||
<Component { ...pageProps }/>
|
||||
</WagmiConfig>
|
||||
<Web3Modal
|
||||
projectId={ PROJECT_ID }
|
||||
ethereumClient={ ethereumClient }
|
||||
themeZIndex={ 1200 }
|
||||
/>
|
||||
<Component { ...pageProps }/>
|
||||
</SocketProvider>
|
||||
</ScrollDirectionProvider>
|
||||
<ReactQueryDevtools/>
|
||||
|
||||
+13
-5
@@ -1,8 +1,10 @@
|
||||
import type { Abi } from 'abitype';
|
||||
|
||||
export interface SmartContract {
|
||||
deployed_bytecode: string | null;
|
||||
creation_bytecode: string | null;
|
||||
is_self_destructed: boolean;
|
||||
abi: Array<Record<string, unknown>> | null;
|
||||
abi: Abi | null;
|
||||
compiler_version: string | null;
|
||||
evm_version: string | null;
|
||||
optimization_enabled: boolean | null;
|
||||
@@ -11,6 +13,7 @@ export interface SmartContract {
|
||||
verified_at: string | null;
|
||||
is_verified: boolean | null;
|
||||
source_code: string | null;
|
||||
constructor_args: string | null;
|
||||
can_be_visualized_via_sol2uml: boolean | null;
|
||||
}
|
||||
|
||||
@@ -19,9 +22,10 @@ export interface SmartContractMethodBase {
|
||||
outputs: Array<SmartContractMethodOutput>;
|
||||
constant: boolean;
|
||||
name: string;
|
||||
stateMutability: string;
|
||||
stateMutability: 'view' | 'nonpayable' | 'payable';
|
||||
type: 'function';
|
||||
payable: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface SmartContractReadMethod extends SmartContractMethodBase {
|
||||
@@ -29,19 +33,23 @@ export interface SmartContractReadMethod extends SmartContractMethodBase {
|
||||
}
|
||||
|
||||
export interface SmartContractWriteFallback {
|
||||
payable: true;
|
||||
stateMutability: 'payable';
|
||||
type: 'fallback';
|
||||
}
|
||||
|
||||
export type SmartContractWriteMethod = SmartContractMethodBase | SmartContractWriteFallback;
|
||||
export interface SmartContractWriteReceive {
|
||||
stateMutability: 'payable';
|
||||
type: 'receive';
|
||||
}
|
||||
|
||||
export type SmartContractWriteMethod = SmartContractMethodBase | SmartContractWriteFallback | SmartContractWriteReceive;
|
||||
|
||||
export type SmartContractMethod = SmartContractReadMethod | SmartContractWriteMethod;
|
||||
|
||||
export interface SmartContractMethodInput {
|
||||
internalType: string;
|
||||
name: string;
|
||||
type: string;
|
||||
type: 'address' | 'uint256' | 'bool';
|
||||
}
|
||||
|
||||
export interface SmartContractMethodOutput extends SmartContractMethodInput {
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { useColorModeValue } from '@chakra-ui/react';
|
||||
import {
|
||||
EthereumClient,
|
||||
modalConnectors,
|
||||
walletConnectProvider,
|
||||
} from '@web3modal/ethereum';
|
||||
import { Web3Modal } from '@web3modal/react';
|
||||
import React from 'react';
|
||||
import type { Chain } from 'wagmi';
|
||||
import { configureChains, createClient, WagmiConfig } from 'wagmi';
|
||||
|
||||
import type { RoutedSubTab } from 'ui/shared/RoutedTabs/types';
|
||||
|
||||
@@ -13,11 +22,53 @@ const TAB_LIST_PROPS = {
|
||||
columnGap: 3,
|
||||
};
|
||||
|
||||
export const poa: Chain = {
|
||||
id: 99,
|
||||
name: 'POA',
|
||||
network: 'poa',
|
||||
nativeCurrency: {
|
||||
decimals: 18,
|
||||
name: 'POA',
|
||||
symbol: 'POA',
|
||||
},
|
||||
rpcUrls: {
|
||||
'default': { http: [ 'https://core.poa.network' ] },
|
||||
},
|
||||
blockExplorers: {
|
||||
'default': { name: 'Blockscout', url: 'https://blockscout.com/poa/core' },
|
||||
},
|
||||
};
|
||||
|
||||
const chains = [ poa ];
|
||||
|
||||
const PROJECT_ID = 'b4ed81be141093911032944632465175';
|
||||
// Wagmi client
|
||||
const { provider } = configureChains(chains, [
|
||||
walletConnectProvider({ projectId: PROJECT_ID }),
|
||||
]);
|
||||
const wagmiClient = createClient({
|
||||
autoConnect: true,
|
||||
connectors: modalConnectors({ appName: 'web3Modal', chains }),
|
||||
provider,
|
||||
});
|
||||
|
||||
// Web3Modal Ethereum Client
|
||||
const ethereumClient = new EthereumClient(wagmiClient, chains);
|
||||
|
||||
const AddressContract = ({ tabs }: Props) => {
|
||||
return (
|
||||
<ContractContextProvider>
|
||||
<RoutedTabs tabs={ tabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>
|
||||
</ContractContextProvider>
|
||||
<WagmiConfig client={ wagmiClient }>
|
||||
<ContractContextProvider>
|
||||
<RoutedTabs tabs={ tabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>
|
||||
</ContractContextProvider>
|
||||
<Web3Modal
|
||||
projectId={ PROJECT_ID }
|
||||
ethereumClient={ ethereumClient }
|
||||
themeZIndex={ 1200 }
|
||||
themeMode={ useColorModeValue('light', 'dark') }
|
||||
themeBackground="themeColor"
|
||||
/>
|
||||
</WagmiConfig>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -77,6 +77,12 @@ const ContractCode = () => {
|
||||
</Grid>
|
||||
) }
|
||||
<Flex flexDir="column" rowGap={ 6 }>
|
||||
{ data.constructor_args && (
|
||||
<RawDataSnippet
|
||||
data={ data.constructor_args }
|
||||
title="Constructor Arguments"
|
||||
/>
|
||||
) }
|
||||
{ data.source_code && (
|
||||
<DynamicContractSourceCode
|
||||
data={ data.source_code }
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { Alert, Button, chakra } from '@chakra-ui/react';
|
||||
import { Alert, Button, Flex } from '@chakra-ui/react';
|
||||
import { useWeb3Modal } from '@web3modal/react';
|
||||
import React from 'react';
|
||||
import { useAccount, useDisconnect } from 'wagmi';
|
||||
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import AddressIcon from 'ui/shared/address/AddressIcon';
|
||||
import AddressLink from 'ui/shared/address/AddressLink';
|
||||
|
||||
const ContractConnectWallet = () => {
|
||||
const { open } = useWeb3Modal();
|
||||
const { address, isDisconnected } = useAccount();
|
||||
const { disconnect } = useDisconnect();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const handleConnect = React.useCallback(() => {
|
||||
open();
|
||||
@@ -29,12 +32,14 @@ const ContractConnectWallet = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>Connected to </span>
|
||||
<AddressIcon address={{ hash: address, is_contract: false }} mx={ 2 }/>
|
||||
<chakra.span fontWeight={ 600 }>{ address }</chakra.span>
|
||||
<Button ml={ 3 } onClick={ handleDisconnect } size="sm" variant="outline">Disconnect</Button>
|
||||
</>
|
||||
<Flex columnGap={ 3 } rowGap={ 3 } alignItems={{ base: 'flex-start', lg: 'center' }} flexDir={{ base: 'column', lg: 'row' }}>
|
||||
<Flex alignItems="center">
|
||||
<span>Connected to </span>
|
||||
<AddressIcon address={{ hash: address, is_contract: false }} mx={ 2 }/>
|
||||
<AddressLink fontWeight={ 600 } hash={ address } truncation={ isMobile ? 'constant' : 'dynamic' }/>
|
||||
</Flex>
|
||||
<Button onClick={ handleDisconnect } size="sm" variant="outline">Disconnect</Button>
|
||||
</Flex>
|
||||
);
|
||||
})();
|
||||
|
||||
|
||||
@@ -43,11 +43,14 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
|
||||
const [ isLoading, setLoading ] = React.useState(false);
|
||||
|
||||
const inputs = React.useMemo(() => {
|
||||
return data.payable && (!('inputs' in data) || data.inputs.length === 0) ? [ {
|
||||
name: 'value',
|
||||
type: appConfig.network.currency.symbol,
|
||||
internalType: appConfig.network.currency.symbol,
|
||||
} as SmartContractMethodInput ] : data.inputs;
|
||||
return [
|
||||
...('inputs' in data ? data.inputs : []),
|
||||
...(data.stateMutability === 'payable' ? [ {
|
||||
name: 'value',
|
||||
type: appConfig.network.currency.symbol,
|
||||
internalType: appConfig.network.currency.symbol,
|
||||
} as SmartContractMethodInput ] : []),
|
||||
];
|
||||
}, [ data ]);
|
||||
|
||||
const { control, handleSubmit, setValue } = useForm<MethodFormFields>({
|
||||
@@ -67,7 +70,7 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setResult(error);
|
||||
setResult('error' in error ? error.error : error);
|
||||
setLoading(false);
|
||||
});
|
||||
}, [ onSubmit, data, inputs ]);
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { SmartContractMethodOutput } from 'types/api/contract';
|
||||
|
||||
import appConfig from 'configs/app/config';
|
||||
import { WEI } from 'lib/consts';
|
||||
import AddressLink from 'ui/shared/address/AddressLink';
|
||||
|
||||
interface Props {
|
||||
data: SmartContractMethodOutput;
|
||||
@@ -31,9 +32,17 @@ const ContractMethodStatic = ({ data }: Props) => {
|
||||
}
|
||||
}, [ data.value ]);
|
||||
|
||||
const content = (() => {
|
||||
if (data.type === 'address' && data.value) {
|
||||
return <AddressLink hash={ data.value }/>;
|
||||
}
|
||||
|
||||
return <chakra.span wordBreak="break-all">({ data.type }): { value }</chakra.span>;
|
||||
})();
|
||||
|
||||
return (
|
||||
<Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 2 } rowGap={ 2 }>
|
||||
<chakra.span wordBreak="break-all">({ data.type }): { value }</chakra.span>
|
||||
{ content }
|
||||
{ isBigInt && <Checkbox onChange={ handleCheckboxChange }>{ label }</Checkbox> }
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -43,7 +43,7 @@ const ContractMethodsAccordion = <T extends SmartContractMethod>({ data, renderC
|
||||
<h2>
|
||||
<AccordionButton px={ 0 } py={ 3 } _hover={{ bgColor: 'inherit' }}>
|
||||
<Box as="span" fontFamily="heading" fontWeight={ 500 } fontSize="lg" mr={ 1 }>
|
||||
{ index + 1 }. { item.type === 'fallback' ? 'fallback' : item.name }
|
||||
{ index + 1 }. { item.type === 'fallback' || item.type === 'receive' ? item.type : item.name }
|
||||
</Box>
|
||||
{ item.type === 'fallback' && (
|
||||
<Tooltip
|
||||
@@ -58,6 +58,21 @@ const ContractMethodsAccordion = <T extends SmartContractMethod>({ data, renderC
|
||||
</Box>
|
||||
</Tooltip>
|
||||
) }
|
||||
{ item.type === 'receive' && (
|
||||
<Tooltip
|
||||
label={ `The receive function is executed on a call to the contract with empty calldata.
|
||||
This is the function that is executed on plain Ether transfers (e.g. via .send() or .transfer()).
|
||||
If no such function exists, but a payable fallback function exists, the fallback function will be called on a plain Ether transfer.
|
||||
If neither a receive Ether nor a payable fallback function is present,
|
||||
the contract cannot receive Ether through regular transactions and throws an exception.` }
|
||||
placement="top"
|
||||
maxW="320px"
|
||||
>
|
||||
<Box cursor="pointer" display="inherit">
|
||||
<Icon as={ infoIcon } boxSize={ 5 }/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
) }
|
||||
<AccordionIcon/>
|
||||
</AccordionButton>
|
||||
</h2>
|
||||
|
||||
@@ -76,6 +76,10 @@ const ContractRead = ({ isProxy }: Props) => {
|
||||
}, [ resultBgColor ]);
|
||||
|
||||
const renderContent = React.useCallback((item: SmartContractReadMethod, index: number, id: number) => {
|
||||
if (item.error) {
|
||||
return <Alert status="error" fontSize="sm">{ item.error }</Alert>;
|
||||
}
|
||||
|
||||
if (item.outputs.some(({ value }) => value)) {
|
||||
return (
|
||||
<Flex flexDir="column" rowGap={ 1 }>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Alert } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
|
||||
import type { ContractMethodWriteResult } from './types';
|
||||
import type { SmartContractWriteMethod } from 'types/api/contract';
|
||||
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
@@ -11,6 +13,7 @@ import DataFetchAlert from 'ui/shared/DataFetchAlert';
|
||||
import { useContractContext } from './context';
|
||||
import ContractConnectWallet from './ContractConnectWallet';
|
||||
import ContractMethodCallable from './ContractMethodCallable';
|
||||
import ContractWriteResult from './ContractWriteResult';
|
||||
|
||||
interface Props {
|
||||
isProxy?: boolean;
|
||||
@@ -35,7 +38,7 @@ const ContractWrite = ({ isProxy }: Props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.type === 'fallback') {
|
||||
if (item.type === 'fallback' || item.type === 'receive') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,13 +48,21 @@ const ContractWrite = ({ isProxy }: Props) => {
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('__>__', { result });
|
||||
console.log('__>__', { result, args });
|
||||
|
||||
return [ [ 'string', 'this is mock' ] ];
|
||||
return { hash: result.hash as string };
|
||||
}, [ contract ]);
|
||||
|
||||
const renderResult = React.useCallback(() => {
|
||||
return <span>result</span>;
|
||||
const renderResult = React.useCallback((item: SmartContractWriteMethod, result: ContractMethodWriteResult) => {
|
||||
if (!result || 'message' in result) {
|
||||
return (
|
||||
<Alert status="error" mt={ 3 } p={ 4 } borderRadius="md" fontSize="sm" wordBreak="break-all">
|
||||
{ result ? result.message : 'No result' }
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return <ContractWriteResult hash={ result.hash as `0x${ string }` }/>;
|
||||
}, []);
|
||||
|
||||
const renderContent = React.useCallback((item: SmartContractWriteMethod, index: number, id: number) => {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Alert, Box, Link } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { useWaitForTransaction } from 'wagmi';
|
||||
|
||||
import link from 'lib/link/link';
|
||||
|
||||
interface Props {
|
||||
hash: `0x${ string }`;
|
||||
}
|
||||
|
||||
const ContractWriteResult = ({ hash }: Props) => {
|
||||
const txInfo = useWaitForTransaction({
|
||||
hash,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('__>__ txInfo', txInfo);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Alert status="info" mt={ 3 } p={ 4 } borderRadius="md" fontSize="sm" flexDir="column" alignItems="flex-start">
|
||||
<Box>Tx hash: <Link href={ link('tx', { id: hash }) }>{ hash }</Link></Box>
|
||||
<Box>Status: { txInfo.status }</Box>
|
||||
</Alert>
|
||||
{ txInfo.error && <Alert status="error" mt={ 3 } p={ 4 } borderRadius="md" fontSize="sm" wordBreak="break-all">{ txInfo.error.message }</Alert> }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ContractWriteResult);
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { ExternalProvider } from '@ethersproject/providers';
|
||||
import type { Contract } from 'ethers';
|
||||
import { ethers } from 'ethers';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { useContract, useProvider, useSigner } from 'wagmi';
|
||||
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
|
||||
@@ -15,11 +14,12 @@ type TContractContext = Contract;
|
||||
const ContractContext = React.createContext<TContractContext | null>(null);
|
||||
|
||||
export function ContractContextProvider({ children }: ProviderProps) {
|
||||
const [ contract, setContract ] = React.useState<TContractContext | null>(null);
|
||||
const router = useRouter();
|
||||
const addressHash = router.query.id?.toString();
|
||||
const provider = useProvider();
|
||||
const { data: signer } = useSigner();
|
||||
|
||||
const { data } = useApiQuery('contract', {
|
||||
const addressHash = router.query.id?.toString();
|
||||
const { data: contractInfo } = useApiQuery('contract', {
|
||||
pathParams: { id: addressHash },
|
||||
queryOptions: {
|
||||
enabled: Boolean(addressHash),
|
||||
@@ -27,18 +27,11 @@ export function ContractContextProvider({ children }: ProviderProps) {
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!addressHash || !data?.abi) {
|
||||
return;
|
||||
}
|
||||
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum as unknown as ExternalProvider);
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addressHash, data.abi, provider);
|
||||
const contractWithSigner = contract.connect(signer);
|
||||
setContract(contractWithSigner);
|
||||
|
||||
}, [ data, addressHash ]);
|
||||
const contract = useContract({
|
||||
address: addressHash,
|
||||
abi: contractInfo?.abi || undefined,
|
||||
signerOrProvider: signer || provider,
|
||||
});
|
||||
|
||||
return (
|
||||
<ContractContext.Provider value={ contract }>
|
||||
|
||||
@@ -5,7 +5,8 @@ import type { ResourceError } from 'lib/api/resources';
|
||||
export type MethodFormFields = Record<string, string>;
|
||||
|
||||
export type ContractMethodReadResult = SmartContractQueryMethodRead | ResourceError;
|
||||
export type ContractMethodWriteResult = unknown;
|
||||
|
||||
export type ContractMethodWriteResult = Error | { hash: string } | undefined;
|
||||
|
||||
export type ContractMethodCallResult<T extends SmartContractMethod> =
|
||||
T extends { method_id: string } ? ContractMethodReadResult : ContractMethodWriteResult;
|
||||
|
||||
@@ -12,6 +12,7 @@ const TxRevertReason = (props: Props) => {
|
||||
const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
|
||||
|
||||
if ('raw' in props) {
|
||||
const decoded = hexToUtf8(props.raw);
|
||||
return (
|
||||
<Grid
|
||||
bgColor={ bgColor }
|
||||
@@ -25,8 +26,12 @@ const TxRevertReason = (props: Props) => {
|
||||
>
|
||||
<GridItem fontWeight={ 500 }>Raw:</GridItem>
|
||||
<GridItem>{ props.raw }</GridItem>
|
||||
<GridItem fontWeight={ 500 }>Decoded:</GridItem>
|
||||
<GridItem>{ hexToUtf8(props.raw) }</GridItem>
|
||||
{ decoded.replace(/\s|\0/g, '') && (
|
||||
<>
|
||||
<GridItem fontWeight={ 500 }>Decoded:</GridItem>
|
||||
<GridItem>{ decoded }</GridItem>
|
||||
</>
|
||||
) }
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user